fabric 5.3.0 → 6.0.0-beta10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (634) hide show
  1. package/.babelrc +11 -0
  2. package/.babelrcAlt +19 -0
  3. package/.browserslistrc +5 -0
  4. package/.eslintignore +3 -0
  5. package/.eslintrc.js +51 -0
  6. package/.eslintrc.json +38 -46
  7. package/.eslintrc_tests +12 -0
  8. package/.gitattributes +2 -0
  9. package/.gitpod.yml +17 -1
  10. package/.prettierignore +19 -0
  11. package/.prettierrc +4 -0
  12. package/CHANGELOG.md +615 -189
  13. package/CONTRIBUTING.md +233 -59
  14. package/README.md +200 -235
  15. package/babel-jest.config.js +6 -0
  16. package/bower.json +1 -3
  17. package/dist/fabric.d.ts +54 -0
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.js +28452 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/index.min.js +1 -0
  22. package/dist/index.mjs +28385 -0
  23. package/dist/index.mjs.map +1 -0
  24. package/dist/index.node.cjs +28538 -0
  25. package/dist/index.node.cjs.map +1 -0
  26. package/dist/index.node.d.ts +20 -0
  27. package/dist/index.node.mjs +28477 -0
  28. package/dist/index.node.mjs.map +1 -0
  29. package/dist/src/ClassRegistry.d.ts +13 -0
  30. package/dist/src/Collection.d.ts +136 -0
  31. package/dist/src/CommonMethods.d.ts +32 -0
  32. package/dist/src/EventTypeDefs.d.ts +227 -0
  33. package/dist/src/Intersection.d.ts +112 -0
  34. package/dist/src/Observable.d.ts +60 -0
  35. package/dist/src/Pattern/Pattern.d.ts +99 -0
  36. package/dist/src/Pattern/index.d.ts +3 -0
  37. package/dist/src/Pattern/types.d.ts +9 -0
  38. package/dist/src/Point.d.ts +232 -0
  39. package/dist/src/Shadow.d.ts +96 -0
  40. package/dist/src/brushes/BaseBrush.d.ts +101 -0
  41. package/dist/src/brushes/CircleBrush.d.ts +44 -0
  42. package/dist/src/brushes/CircleBrush.test.d.ts +2 -0
  43. package/dist/src/brushes/PatternBrush.d.ts +23 -0
  44. package/dist/src/brushes/PencilBrush.d.ts +92 -0
  45. package/dist/src/brushes/SprayBrush.d.ts +74 -0
  46. package/dist/src/brushes/typedefs.d.ts +18 -0
  47. package/dist/src/cache.d.ts +47 -0
  48. package/dist/src/canvas/Canvas.d.ts +364 -0
  49. package/dist/src/canvas/DOMManagers/CanvasDOMManager.d.ts +29 -0
  50. package/dist/src/canvas/DOMManagers/StaticCanvasDOMManager.d.ts +29 -0
  51. package/dist/src/canvas/DOMManagers/util.d.ts +24 -0
  52. package/dist/src/canvas/DOMManagers/util.spec.d.ts +2 -0
  53. package/dist/src/canvas/SelectableCanvas.d.ts +723 -0
  54. package/dist/src/canvas/StaticCanvas.d.ts +747 -0
  55. package/dist/src/canvas/TextEditingManager.d.ts +21 -0
  56. package/dist/src/canvas/canvas_gestures.mixin.d.ts +2 -0
  57. package/dist/src/color/Color.d.ts +152 -0
  58. package/dist/src/color/color_map.d.ts +155 -0
  59. package/dist/src/color/constants.d.ts +104 -0
  60. package/dist/src/color/typedefs.d.ts +16 -0
  61. package/dist/src/color/util.d.ts +27 -0
  62. package/dist/src/config.d.ts +115 -0
  63. package/dist/src/constants.d.ts +21 -0
  64. package/dist/src/controls/Control.d.ts +229 -0
  65. package/dist/src/controls/changeWidth.d.ts +13 -0
  66. package/dist/src/controls/commonControls.d.ts +28 -0
  67. package/dist/src/controls/controlRendering.d.ts +29 -0
  68. package/dist/src/controls/drag.d.ts +12 -0
  69. package/dist/src/controls/fireEvent.d.ts +3 -0
  70. package/dist/src/controls/index.d.ts +13 -0
  71. package/dist/src/controls/polyControl.d.ts +5 -0
  72. package/dist/src/controls/rotate.d.ts +12 -0
  73. package/dist/src/controls/scale.d.ts +47 -0
  74. package/dist/src/controls/scaleSkew.d.ts +39 -0
  75. package/dist/src/controls/skew.d.ts +33 -0
  76. package/dist/src/controls/util.d.ts +41 -0
  77. package/dist/src/controls/wrapWithFireEvent.d.ts +8 -0
  78. package/dist/src/controls/wrapWithFixedAnchor.d.ts +9 -0
  79. package/dist/src/env/browser.d.ts +3 -0
  80. package/dist/src/env/index.d.ts +28 -0
  81. package/dist/src/env/node.d.ts +6 -0
  82. package/dist/src/env/types.d.ts +15 -0
  83. package/dist/src/filters/BaseFilter.d.ts +160 -0
  84. package/dist/src/filters/BlendColor.d.ts +81 -0
  85. package/dist/src/filters/BlendImage.d.ts +93 -0
  86. package/dist/src/filters/Blur.d.ts +52 -0
  87. package/dist/src/filters/Boilerplate.d.ts +48 -0
  88. package/dist/src/filters/Brightness.d.ts +48 -0
  89. package/dist/src/filters/Canvas2dFilterBackend.d.ts +27 -0
  90. package/dist/src/filters/ColorMatrix.d.ts +64 -0
  91. package/dist/src/filters/ColorMatrixFilters.d.ts +537 -0
  92. package/dist/src/filters/Composed.d.ts +46 -0
  93. package/dist/src/filters/Contrast.d.ts +46 -0
  94. package/dist/src/filters/Convolute.d.ts +83 -0
  95. package/dist/src/filters/FilterBackend.d.ts +15 -0
  96. package/dist/src/filters/GLProbes/GLProbe.d.ts +7 -0
  97. package/dist/src/filters/GLProbes/NodeGLProbe.d.ts +11 -0
  98. package/dist/src/filters/GLProbes/WebGLProbe.d.ts +20 -0
  99. package/dist/src/filters/Gamma.d.ts +55 -0
  100. package/dist/src/filters/Grayscale.d.ts +47 -0
  101. package/dist/src/filters/HueRotation.d.ts +25 -0
  102. package/dist/src/filters/Invert.d.ts +56 -0
  103. package/dist/src/filters/Noise.d.ts +55 -0
  104. package/dist/src/filters/Pixelate.d.ts +45 -0
  105. package/dist/src/filters/RemoveColor.d.ts +64 -0
  106. package/dist/src/filters/Resize.d.ts +137 -0
  107. package/dist/src/filters/Saturation.d.ts +49 -0
  108. package/dist/src/filters/Vibrance.d.ts +49 -0
  109. package/dist/src/filters/WebGLFilterBackend.d.ts +128 -0
  110. package/dist/src/filters/filters.d.ts +21 -0
  111. package/dist/src/filters/index.d.ts +7 -0
  112. package/dist/src/filters/shaders/baseFilter.d.ts +4 -0
  113. package/dist/src/filters/shaders/blendColor.d.ts +13 -0
  114. package/dist/src/filters/shaders/blendImage.d.ts +3 -0
  115. package/dist/src/filters/shaders/blur.d.ts +2 -0
  116. package/dist/src/filters/shaders/brightness.d.ts +2 -0
  117. package/dist/src/filters/shaders/colorMatrix.d.ts +2 -0
  118. package/dist/src/filters/shaders/constrast.d.ts +2 -0
  119. package/dist/src/filters/shaders/convolute.d.ts +11 -0
  120. package/dist/src/filters/shaders/gamma.d.ts +2 -0
  121. package/dist/src/filters/shaders/grayscale.d.ts +3 -0
  122. package/dist/src/filters/shaders/invert.d.ts +2 -0
  123. package/dist/src/filters/shaders/noise.d.ts +2 -0
  124. package/dist/src/filters/shaders/pixelate.d.ts +2 -0
  125. package/dist/src/filters/shaders/removeColor.d.ts +2 -0
  126. package/dist/src/filters/shaders/saturation.d.ts +2 -0
  127. package/dist/src/filters/shaders/vibrance.d.ts +2 -0
  128. package/dist/src/filters/typedefs.d.ts +48 -0
  129. package/dist/src/filters/utils.d.ts +3 -0
  130. package/dist/src/gradient/Gradient.d.ts +150 -0
  131. package/dist/src/gradient/constants.d.ts +15 -0
  132. package/dist/src/gradient/index.d.ts +3 -0
  133. package/dist/src/gradient/parser/index.d.ts +4 -0
  134. package/dist/src/gradient/parser/misc.d.ts +4 -0
  135. package/dist/src/gradient/parser/parseColorStops.d.ts +3 -0
  136. package/dist/src/gradient/parser/parseCoords.d.ts +17 -0
  137. package/dist/src/gradient/typedefs.d.ts +93 -0
  138. package/dist/src/mixins/eraser_brush.mixin.d.ts +2 -0
  139. package/dist/src/parkinglot/canvas_animation.mixin.d.ts +2 -0
  140. package/dist/src/parkinglot/straighten.d.ts +2 -0
  141. package/dist/src/parser/applyViewboxTransform.d.ts +5 -0
  142. package/dist/src/parser/attributes.d.ts +6 -0
  143. package/dist/src/parser/constants.d.ts +53 -0
  144. package/dist/src/parser/doesSomeParentMatch.d.ts +2 -0
  145. package/dist/src/parser/elementById.d.ts +6 -0
  146. package/dist/src/parser/elementMatchesRule.d.ts +5 -0
  147. package/dist/src/parser/elements_parser.d.ts +3 -0
  148. package/dist/src/parser/getCSSRules.d.ts +7 -0
  149. package/dist/src/parser/getGlobalStylesForElement.d.ts +5 -0
  150. package/dist/src/parser/getGradientDefs.d.ts +7 -0
  151. package/dist/src/parser/getMultipleNodes.d.ts +2 -0
  152. package/dist/src/parser/getSvgRegex.d.ts +2 -0
  153. package/dist/src/parser/hasAncestorWithNodeName.d.ts +2 -0
  154. package/dist/src/parser/index.d.ts +9 -0
  155. package/dist/src/parser/loadSVGFromString.d.ts +18 -0
  156. package/dist/src/parser/loadSVGFromURL.d.ts +19 -0
  157. package/dist/src/parser/normalizeAttr.d.ts +2 -0
  158. package/dist/src/parser/normalizeValue.d.ts +2 -0
  159. package/dist/src/parser/parseAttributes.d.ts +9 -0
  160. package/dist/src/parser/parseFontDeclaration.d.ts +10 -0
  161. package/dist/src/parser/parsePointsAttribute.d.ts +12 -0
  162. package/dist/src/parser/parseSVGDocument.d.ts +23 -0
  163. package/dist/src/parser/parseStyleAttribute.d.ts +9 -0
  164. package/dist/src/parser/parseStyleObject.d.ts +2 -0
  165. package/dist/src/parser/parseStyleString.d.ts +2 -0
  166. package/dist/src/parser/parseTransformAttribute.d.ts +11 -0
  167. package/dist/src/parser/parseUseDirectives.d.ts +2 -0
  168. package/dist/src/parser/percent.d.ts +9 -0
  169. package/dist/src/parser/recursivelyParseGradientsXlink.d.ts +2 -0
  170. package/dist/src/parser/selectorMatches.d.ts +2 -0
  171. package/dist/src/parser/setStrokeFillOpacity.d.ts +6 -0
  172. package/dist/src/parser/typedefs.d.ts +9 -0
  173. package/dist/src/shapes/ActiveSelection.d.ts +83 -0
  174. package/dist/src/shapes/Circle.d.ts +99 -0
  175. package/dist/src/shapes/Ellipse.d.ts +84 -0
  176. package/dist/src/shapes/Group.d.ts +407 -0
  177. package/dist/src/shapes/IText/DraggableTextDelegate.d.ts +78 -0
  178. package/dist/src/shapes/IText/IText.d.ts +336 -0
  179. package/dist/src/shapes/IText/ITextBehavior.d.ts +287 -0
  180. package/dist/src/shapes/IText/ITextClickBehavior.d.ts +73 -0
  181. package/dist/src/shapes/IText/ITextKeyBehavior.d.ts +195 -0
  182. package/dist/src/shapes/IText/constants.d.ts +13 -0
  183. package/dist/src/shapes/Image.d.ts +309 -0
  184. package/dist/src/shapes/Line.d.ts +121 -0
  185. package/dist/src/shapes/Object/AnimatableObject.d.ts +33 -0
  186. package/dist/src/shapes/Object/FabricObject.d.ts +11 -0
  187. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.d.ts +74 -0
  188. package/dist/src/shapes/Object/InteractiveObject.d.ts +296 -0
  189. package/dist/src/shapes/Object/Object.d.ts +599 -0
  190. package/dist/src/shapes/Object/ObjectGeometry.d.ts +327 -0
  191. package/dist/src/shapes/Object/ObjectOrigin.d.ts +109 -0
  192. package/dist/src/shapes/Object/StackedObject.d.ts +72 -0
  193. package/dist/src/shapes/Object/defaultValues.d.ts +76 -0
  194. package/dist/src/shapes/Object/types/BaseProps.d.ts +84 -0
  195. package/dist/src/shapes/Object/types/BorderProps.d.ts +37 -0
  196. package/dist/src/shapes/Object/types/ControlProps.d.ts +62 -0
  197. package/dist/src/shapes/Object/types/FabricObjectProps.d.ts +96 -0
  198. package/dist/src/shapes/Object/types/FillStrokeProps.d.ts +80 -0
  199. package/dist/src/shapes/Object/types/LockInteractionProps.d.ts +51 -0
  200. package/dist/src/shapes/Object/types/ObjectProps.d.ts +42 -0
  201. package/dist/src/shapes/Object/types/SerializedObjectProps.d.ts +66 -0
  202. package/dist/src/shapes/Object/types/index.d.ts +6 -0
  203. package/dist/src/shapes/Path.d.ts +214 -0
  204. package/dist/src/shapes/Polygon.d.ts +10 -0
  205. package/dist/src/shapes/Polyline.d.ts +147 -0
  206. package/dist/src/shapes/Rect.d.ts +82 -0
  207. package/dist/src/shapes/Text/StyledText.d.ts +123 -0
  208. package/dist/src/shapes/Text/Text.d.ts +688 -0
  209. package/dist/src/shapes/Text/TextSVGExportMixin.d.ts +32 -0
  210. package/dist/src/shapes/Text/constants.d.ts +13 -0
  211. package/dist/src/shapes/Textbox.d.ts +204 -0
  212. package/dist/src/shapes/Triangle.d.ts +26 -0
  213. package/dist/src/typedefs.d.ts +96 -0
  214. package/dist/src/util/animation/AnimationBase.d.ts +54 -0
  215. package/dist/src/util/animation/AnimationFrameProvider.d.ts +3 -0
  216. package/dist/src/util/animation/AnimationRegistry.d.ts +29 -0
  217. package/dist/src/util/animation/ArrayAnimation.d.ts +10 -0
  218. package/dist/src/util/animation/ColorAnimation.d.ts +11 -0
  219. package/dist/src/util/animation/ValueAnimation.d.ts +10 -0
  220. package/dist/src/util/animation/animate.d.ts +37 -0
  221. package/dist/src/util/animation/easing.d.ts +130 -0
  222. package/dist/src/util/animation/index.d.ts +3 -0
  223. package/dist/src/util/animation/types.d.ts +87 -0
  224. package/dist/src/util/applyMixins.d.ts +8 -0
  225. package/dist/src/util/dom_event.d.ts +5 -0
  226. package/dist/src/util/dom_misc.d.ts +12 -0
  227. package/dist/src/util/dom_request.d.ts +14 -0
  228. package/dist/src/util/dom_style.d.ts +7 -0
  229. package/dist/src/util/index.d.ts +36 -0
  230. package/dist/src/util/internals/cleanupSvgAttribute.d.ts +2 -0
  231. package/dist/src/util/internals/cleanupSvgAttribute.test.d.ts +2 -0
  232. package/dist/src/util/internals/cloneDeep.d.ts +2 -0
  233. package/dist/src/util/internals/cloneDeep.test.d.ts +2 -0
  234. package/dist/src/util/internals/getRandomInt.d.ts +8 -0
  235. package/dist/src/util/internals/getRandomInt.test.d.ts +2 -0
  236. package/dist/src/util/internals/ifNaN.d.ts +8 -0
  237. package/dist/src/util/internals/index.d.ts +4 -0
  238. package/dist/src/util/internals/removeFromArray.d.ts +9 -0
  239. package/dist/src/util/internals/uid.d.ts +2 -0
  240. package/dist/src/util/lang_string.d.ts +22 -0
  241. package/dist/src/util/misc/boundingBoxFromPoints.d.ts +9 -0
  242. package/dist/src/util/misc/capValue.d.ts +2 -0
  243. package/dist/src/util/misc/cos.d.ts +10 -0
  244. package/dist/src/util/misc/dom.d.ts +28 -0
  245. package/dist/src/util/misc/findScaleTo.d.ts +20 -0
  246. package/dist/src/util/misc/groupSVGElements.d.ts +9 -0
  247. package/dist/src/util/misc/isTransparent.d.ts +11 -0
  248. package/dist/src/util/misc/matrix.d.ts +168 -0
  249. package/dist/src/util/misc/mergeClipPaths.d.ts +23 -0
  250. package/dist/src/util/misc/objectEnlive.d.ts +41 -0
  251. package/dist/src/util/misc/objectTransforms.d.ts +68 -0
  252. package/dist/src/util/misc/pick.d.ts +9 -0
  253. package/dist/src/util/misc/planeChange.d.ts +81 -0
  254. package/dist/src/util/misc/projectStroke/StrokeLineCapProjections.d.ts +52 -0
  255. package/dist/src/util/misc/projectStroke/StrokeLineJoinProjections.d.ts +82 -0
  256. package/dist/src/util/misc/projectStroke/StrokeProjectionsBase.d.ts +26 -0
  257. package/dist/src/util/misc/projectStroke/index.d.ts +12 -0
  258. package/dist/src/util/misc/projectStroke/types.d.ts +23 -0
  259. package/dist/src/util/misc/radiansDegreesConversion.d.ts +14 -0
  260. package/dist/src/util/misc/resolveOrigin.d.ts +9 -0
  261. package/dist/src/util/misc/rotatePoint.d.ts +12 -0
  262. package/dist/src/util/misc/sin.d.ts +10 -0
  263. package/dist/src/util/misc/svgParsing.d.ts +45 -0
  264. package/dist/src/util/misc/textStyles.d.ts +32 -0
  265. package/dist/src/util/misc/toFixed.d.ts +8 -0
  266. package/dist/src/util/misc/vectors.d.ts +58 -0
  267. package/dist/src/util/path/index.d.ts +96 -0
  268. package/dist/src/util/path/regex.d.ts +2 -0
  269. package/dist/src/util/path/typechecks.d.ts +24 -0
  270. package/dist/src/util/path/typedefs.d.ts +220 -0
  271. package/dist/src/util/transform_matrix_removal.d.ts +14 -0
  272. package/dist/src/util/typeAssertions.d.ts +19 -0
  273. package/e2e/site/index.html +25 -0
  274. package/e2e/utils/objects.ts +36 -0
  275. package/fabric.ts +72 -0
  276. package/index.node.ts +43 -0
  277. package/index.ts +1 -0
  278. package/jest.config.js +194 -0
  279. package/lib/aligning_guidelines.js +2 -2
  280. package/package.json +110 -40
  281. package/playwright.config.ts +64 -0
  282. package/publish.js +0 -26
  283. package/rollup.config.mjs +99 -0
  284. package/rollup.test.config.js +24 -0
  285. package/scripts/build.mjs +50 -0
  286. package/scripts/buildLock.mjs +115 -0
  287. package/scripts/buildReporter.mjs +15 -0
  288. package/scripts/buildStats.mjs +139 -0
  289. package/scripts/dirname.mjs +14 -0
  290. package/scripts/git.mjs +36 -0
  291. package/scripts/index.mjs +564 -0
  292. package/scripts/sandbox.mjs +149 -0
  293. package/src/ClassRegistry.ts +56 -0
  294. package/src/Collection.ts +346 -0
  295. package/src/CommonMethods.ts +63 -0
  296. package/src/EventTypeDefs.ts +298 -0
  297. package/src/Intersection.ts +302 -0
  298. package/src/Observable.ts +181 -0
  299. package/src/Pattern/Pattern.ts +207 -0
  300. package/src/Pattern/index.ts +2 -0
  301. package/src/Pattern/types.ts +17 -0
  302. package/src/Point.ts +388 -0
  303. package/src/Shadow.ts +214 -0
  304. package/src/brushes/{base_brush.class.js → BaseBrush.ts} +63 -42
  305. package/src/brushes/CircleBrush.test.ts +11 -0
  306. package/src/brushes/CircleBrush.ts +140 -0
  307. package/src/brushes/PatternBrush.ts +70 -0
  308. package/src/brushes/PencilBrush.ts +300 -0
  309. package/src/brushes/SprayBrush.ts +214 -0
  310. package/src/brushes/typedefs.ts +18 -0
  311. package/src/cache.ts +90 -0
  312. package/src/canvas/Canvas.ts +1598 -0
  313. package/src/canvas/DOMManagers/CanvasDOMManager.ts +124 -0
  314. package/src/canvas/DOMManagers/StaticCanvasDOMManager.ts +80 -0
  315. package/src/canvas/DOMManagers/util.spec.ts +26 -0
  316. package/src/canvas/DOMManagers/util.ts +98 -0
  317. package/src/canvas/SelectableCanvas.ts +1506 -0
  318. package/src/canvas/StaticCanvas.ts +1634 -0
  319. package/src/canvas/TextEditingManager.ts +70 -0
  320. package/src/canvas/canvas_gestures.mixin.ts +207 -0
  321. package/src/color/Color.ts +320 -0
  322. package/src/color/color_map.ts +154 -0
  323. package/src/color/constants.ts +107 -0
  324. package/src/color/typedefs.ts +18 -0
  325. package/src/color/util.ts +93 -0
  326. package/src/config.ts +159 -0
  327. package/src/constants.ts +29 -0
  328. package/src/controls/Control.ts +385 -0
  329. package/src/controls/changeWidth.ts +53 -0
  330. package/src/controls/commonControls.ts +105 -0
  331. package/src/controls/controlRendering.ts +138 -0
  332. package/src/controls/drag.ts +32 -0
  333. package/src/controls/fireEvent.ts +18 -0
  334. package/src/controls/index.ts +22 -0
  335. package/src/controls/polyControl.ts +135 -0
  336. package/src/controls/rotate.ts +87 -0
  337. package/src/controls/scale.ts +277 -0
  338. package/src/controls/scaleSkew.ts +92 -0
  339. package/src/controls/skew.ts +243 -0
  340. package/src/controls/util.ts +155 -0
  341. package/src/controls/wrapWithFireEvent.ts +25 -0
  342. package/src/controls/wrapWithFixedAnchor.ts +20 -0
  343. package/src/env/browser.ts +32 -0
  344. package/src/env/index.ts +38 -0
  345. package/src/env/node.ts +58 -0
  346. package/src/env/types.ts +15 -0
  347. package/src/filters/{base_filter.class.js → BaseFilter.ts} +203 -151
  348. package/src/filters/BlendColor.ts +219 -0
  349. package/src/filters/BlendImage.ts +230 -0
  350. package/src/filters/Blur.ts +181 -0
  351. package/src/filters/Boilerplate.ts +94 -0
  352. package/src/filters/Brightness.ts +85 -0
  353. package/src/filters/Canvas2dFilterBackend.ts +65 -0
  354. package/src/filters/ColorMatrix.ts +147 -0
  355. package/src/filters/ColorMatrixFilters.ts +79 -0
  356. package/src/filters/Composed.ts +78 -0
  357. package/src/filters/Contrast.ts +84 -0
  358. package/src/filters/Convolute.ts +186 -0
  359. package/src/filters/FilterBackend.ts +38 -0
  360. package/src/filters/GLProbes/GLProbe.ts +7 -0
  361. package/src/filters/GLProbes/NodeGLProbe.ts +15 -0
  362. package/src/filters/GLProbes/WebGLProbe.ts +47 -0
  363. package/src/filters/Gamma.ts +112 -0
  364. package/src/filters/Grayscale.ts +104 -0
  365. package/src/filters/HueRotation.ts +64 -0
  366. package/src/filters/Invert.ts +101 -0
  367. package/src/filters/Noise.ts +96 -0
  368. package/src/filters/Pixelate.ts +98 -0
  369. package/src/filters/RemoveColor.ts +137 -0
  370. package/src/filters/Resize.ts +540 -0
  371. package/src/filters/Saturation.ts +89 -0
  372. package/src/filters/Vibrance.ts +90 -0
  373. package/src/filters/WebGLFilterBackend.ts +456 -0
  374. package/src/filters/filters.ts +28 -0
  375. package/src/filters/index.ts +12 -0
  376. package/src/filters/shaders/baseFilter.ts +17 -0
  377. package/src/filters/shaders/blendColor.ts +33 -0
  378. package/src/filters/shaders/blendImage.ts +32 -0
  379. package/src/filters/shaders/blur.ts +24 -0
  380. package/src/filters/shaders/brightness.ts +11 -0
  381. package/src/filters/shaders/colorMatrix.ts +12 -0
  382. package/src/filters/shaders/constrast.ts +11 -0
  383. package/src/filters/shaders/convolute.ts +154 -0
  384. package/src/filters/shaders/gamma.ts +15 -0
  385. package/src/filters/shaders/grayscale.ts +36 -0
  386. package/src/filters/shaders/invert.ts +19 -0
  387. package/src/filters/shaders/noise.ts +16 -0
  388. package/src/filters/shaders/pixelate.ts +19 -0
  389. package/src/filters/shaders/removeColor.ts +13 -0
  390. package/src/filters/shaders/saturation.ts +15 -0
  391. package/src/filters/shaders/vibrance.ts +16 -0
  392. package/src/filters/typedefs.ts +59 -0
  393. package/src/filters/utils.ts +7 -0
  394. package/src/gradient/Gradient.ts +409 -0
  395. package/src/gradient/constants.ts +12 -0
  396. package/src/gradient/index.ts +2 -0
  397. package/src/gradient/parser/index.ts +3 -0
  398. package/src/gradient/parser/misc.ts +13 -0
  399. package/src/gradient/parser/parseColorStops.ts +56 -0
  400. package/src/gradient/parser/parseCoords.ts +73 -0
  401. package/src/gradient/typedefs.ts +104 -0
  402. package/src/mixins/{eraser_brush.mixin.js → eraser_brush.mixin.ts} +350 -239
  403. package/src/parkinglot/canvas_animation.mixin.ts +121 -0
  404. package/src/parkinglot/straighten.ts +58 -0
  405. package/src/parser/applyViewboxTransform.ts +158 -0
  406. package/src/parser/attributes.ts +25 -0
  407. package/src/parser/constants.ts +116 -0
  408. package/src/parser/doesSomeParentMatch.ts +18 -0
  409. package/src/parser/elementById.ts +21 -0
  410. package/src/parser/elementMatchesRule.ts +16 -0
  411. package/src/parser/elements_parser.ts +158 -0
  412. package/src/parser/getCSSRules.ts +61 -0
  413. package/src/parser/getGlobalStylesForElement.ts +19 -0
  414. package/src/parser/getGradientDefs.ts +31 -0
  415. package/src/parser/getMultipleNodes.ts +15 -0
  416. package/src/parser/getSvgRegex.ts +3 -0
  417. package/src/parser/hasAncestorWithNodeName.ts +14 -0
  418. package/src/parser/index.ts +8 -0
  419. package/src/parser/loadSVGFromString.ts +29 -0
  420. package/src/parser/loadSVGFromURL.ts +47 -0
  421. package/src/parser/normalizeAttr.ts +10 -0
  422. package/src/parser/normalizeValue.ts +64 -0
  423. package/src/parser/parseAttributes.ts +90 -0
  424. package/src/parser/parseFontDeclaration.ts +44 -0
  425. package/src/parser/parsePointsAttribute.ts +34 -0
  426. package/src/parser/parseSVGDocument.ts +118 -0
  427. package/src/parser/parseStyleAttribute.ts +27 -0
  428. package/src/parser/parseStyleObject.ts +15 -0
  429. package/src/parser/parseStyleString.ts +16 -0
  430. package/src/parser/parseTransformAttribute.ts +94 -0
  431. package/src/parser/parseUseDirectives.ts +78 -0
  432. package/src/parser/percent.ts +27 -0
  433. package/src/parser/recursivelyParseGradientsXlink.ts +42 -0
  434. package/src/parser/selectorMatches.ts +25 -0
  435. package/src/parser/setStrokeFillOpacity.ts +40 -0
  436. package/src/parser/typedefs.ts +13 -0
  437. package/src/shapes/ActiveSelection.ts +192 -0
  438. package/src/shapes/Circle.ts +236 -0
  439. package/src/shapes/Ellipse.ts +177 -0
  440. package/src/shapes/Group.ts +1103 -0
  441. package/src/shapes/IText/DraggableTextDelegate.ts +385 -0
  442. package/src/shapes/IText/IText.ts +696 -0
  443. package/src/shapes/IText/ITextBehavior.ts +1073 -0
  444. package/src/shapes/IText/ITextClickBehavior.ts +292 -0
  445. package/src/shapes/IText/ITextKeyBehavior.ts +675 -0
  446. package/src/shapes/IText/constants.ts +53 -0
  447. package/src/shapes/Image.ts +848 -0
  448. package/src/shapes/Line.ts +285 -0
  449. package/src/shapes/Object/AnimatableObject.ts +103 -0
  450. package/src/shapes/Object/FabricObject.ts +29 -0
  451. package/src/shapes/Object/FabricObjectSVGExportMixin.ts +278 -0
  452. package/src/shapes/Object/InteractiveObject.ts +669 -0
  453. package/src/shapes/Object/Object.ts +1589 -0
  454. package/src/shapes/Object/ObjectGeometry.ts +814 -0
  455. package/src/shapes/Object/ObjectOrigin.ts +277 -0
  456. package/src/shapes/Object/StackedObject.ts +206 -0
  457. package/src/shapes/Object/defaultValues.ts +110 -0
  458. package/src/shapes/Object/types/BaseProps.ts +96 -0
  459. package/src/shapes/Object/types/BorderProps.ts +40 -0
  460. package/src/shapes/Object/types/ControlProps.ts +69 -0
  461. package/src/shapes/Object/types/FabricObjectProps.ts +111 -0
  462. package/src/shapes/Object/types/FillStrokeProps.ts +90 -0
  463. package/src/shapes/Object/types/LockInteractionProps.ts +57 -0
  464. package/src/shapes/Object/types/ObjectProps.ts +49 -0
  465. package/src/shapes/Object/types/SerializedObjectProps.ts +73 -0
  466. package/src/shapes/Object/types/index.ts +8 -0
  467. package/src/shapes/Path.ts +434 -0
  468. package/src/shapes/Polygon.ts +22 -0
  469. package/src/shapes/Polyline.ts +364 -0
  470. package/src/shapes/Rect.ts +230 -0
  471. package/src/shapes/Text/StyledText.ts +323 -0
  472. package/src/shapes/Text/Text.ts +1891 -0
  473. package/src/shapes/Text/TextSVGExportMixin.ts +289 -0
  474. package/src/shapes/Text/constants.ts +111 -0
  475. package/src/shapes/Textbox.ts +526 -0
  476. package/src/shapes/Triangle.ts +62 -0
  477. package/src/typedefs.ts +121 -0
  478. package/src/util/animation/AnimationBase.ts +166 -0
  479. package/src/util/animation/AnimationFrameProvider.ts +9 -0
  480. package/src/util/animation/AnimationRegistry.ts +58 -0
  481. package/src/util/animation/ArrayAnimation.ts +27 -0
  482. package/src/util/animation/ColorAnimation.ts +74 -0
  483. package/src/util/animation/ValueAnimation.ts +29 -0
  484. package/src/util/animation/animate.ts +74 -0
  485. package/src/util/animation/easing.ts +327 -0
  486. package/src/util/animation/index.ts +2 -0
  487. package/src/util/animation/types.ts +136 -0
  488. package/src/util/applyMixins.ts +22 -0
  489. package/src/util/dom_event.ts +28 -0
  490. package/src/util/dom_misc.ts +44 -0
  491. package/src/util/dom_request.ts +64 -0
  492. package/src/util/dom_style.ts +20 -0
  493. package/src/util/index.ts +106 -0
  494. package/src/util/internals/cleanupSvgAttribute.test.ts +16 -0
  495. package/src/util/internals/cleanupSvgAttribute.ts +8 -0
  496. package/src/util/internals/cloneDeep.test.ts +16 -0
  497. package/src/util/internals/cloneDeep.ts +2 -0
  498. package/src/util/internals/getRandomInt.test.ts +33 -0
  499. package/src/util/internals/getRandomInt.ts +8 -0
  500. package/src/util/internals/ifNaN.ts +9 -0
  501. package/src/util/internals/index.ts +3 -0
  502. package/src/util/internals/removeFromArray.ts +14 -0
  503. package/src/util/internals/uid.ts +3 -0
  504. package/src/util/lang_string.ts +79 -0
  505. package/src/util/misc/boundingBoxFromPoints.ts +38 -0
  506. package/src/util/misc/capValue.ts +2 -0
  507. package/src/util/misc/cos.ts +24 -0
  508. package/src/util/misc/dom.ts +55 -0
  509. package/src/util/misc/findScaleTo.ts +29 -0
  510. package/src/util/misc/groupSVGElements.ts +15 -0
  511. package/src/util/misc/isTransparent.ts +28 -0
  512. package/src/util/misc/matrix.ts +313 -0
  513. package/src/util/misc/mergeClipPaths.ts +40 -0
  514. package/src/util/misc/objectEnlive.ts +174 -0
  515. package/src/util/misc/objectTransforms.ts +130 -0
  516. package/src/util/misc/pick.ts +29 -0
  517. package/src/util/misc/planeChange.ts +127 -0
  518. package/src/util/misc/projectStroke/StrokeLineCapProjections.ts +113 -0
  519. package/src/util/misc/projectStroke/StrokeLineJoinProjections.ts +227 -0
  520. package/src/util/misc/projectStroke/StrokeProjectionsBase.ts +76 -0
  521. package/src/util/misc/projectStroke/index.ts +55 -0
  522. package/src/util/misc/projectStroke/types.ts +24 -0
  523. package/src/util/misc/radiansDegreesConversion.ts +18 -0
  524. package/src/util/misc/resolveOrigin.ts +22 -0
  525. package/src/util/misc/rotatePoint.ts +15 -0
  526. package/src/util/misc/sin.ts +26 -0
  527. package/src/util/misc/svgParsing.ts +171 -0
  528. package/src/util/misc/textStyles.ts +132 -0
  529. package/src/util/misc/toFixed.ts +8 -0
  530. package/src/util/misc/vectors.ts +83 -0
  531. package/src/util/path/index.ts +1039 -0
  532. package/src/util/path/regex.ts +39 -0
  533. package/src/util/path/typechecks.ts +145 -0
  534. package/src/util/path/typedefs.ts +305 -0
  535. package/src/util/transform_matrix_removal.ts +61 -0
  536. package/src/util/typeAssertions.ts +78 -0
  537. package/tsconfig.json +106 -0
  538. package/HEADER.js +0 -203
  539. package/build.js +0 -287
  540. package/dist/fabric.js +0 -31187
  541. package/dist/fabric.min.js +0 -1
  542. package/old-travis-reference.yml +0 -97
  543. package/src/brushes/circle_brush.class.js +0 -144
  544. package/src/brushes/pattern_brush.class.js +0 -61
  545. package/src/brushes/pencil_brush.class.js +0 -310
  546. package/src/brushes/spray_brush.class.js +0 -219
  547. package/src/canvas.class.js +0 -1312
  548. package/src/color.class.js +0 -636
  549. package/src/control.class.js +0 -339
  550. package/src/controls.actions.js +0 -740
  551. package/src/controls.render.js +0 -99
  552. package/src/elements_parser.js +0 -152
  553. package/src/filters/2d_backend.class.js +0 -65
  554. package/src/filters/blendcolor_filter.class.js +0 -251
  555. package/src/filters/blendimage_filter.class.js +0 -247
  556. package/src/filters/blur_filter.class.js +0 -217
  557. package/src/filters/brightness_filter.class.js +0 -113
  558. package/src/filters/colormatrix_filter.class.js +0 -159
  559. package/src/filters/composed_filter.class.js +0 -72
  560. package/src/filters/contrast_filter.class.js +0 -113
  561. package/src/filters/convolute_filter.class.js +0 -352
  562. package/src/filters/filter_boilerplate.js +0 -111
  563. package/src/filters/filter_generator.js +0 -85
  564. package/src/filters/gamma_filter.class.js +0 -136
  565. package/src/filters/grayscale_filter.class.js +0 -154
  566. package/src/filters/hue_rotation.class.js +0 -107
  567. package/src/filters/invert_filter.class.js +0 -111
  568. package/src/filters/noise_filter.class.js +0 -134
  569. package/src/filters/pixelate_filter.class.js +0 -137
  570. package/src/filters/removecolor_filter.class.js +0 -173
  571. package/src/filters/resize_filter.class.js +0 -490
  572. package/src/filters/saturate_filter.class.js +0 -119
  573. package/src/filters/vibrance_filter.class.js +0 -122
  574. package/src/filters/webgl_backend.class.js +0 -396
  575. package/src/globalFabric.js +0 -4
  576. package/src/gradient.class.js +0 -490
  577. package/src/intersection.class.js +0 -172
  578. package/src/log.js +0 -11
  579. package/src/mixins/animation.mixin.js +0 -231
  580. package/src/mixins/canvas_dataurl_exporter.mixin.js +0 -97
  581. package/src/mixins/canvas_events.mixin.js +0 -974
  582. package/src/mixins/canvas_gestures.mixin.js +0 -149
  583. package/src/mixins/canvas_grouping.mixin.js +0 -177
  584. package/src/mixins/canvas_serialization.mixin.js +0 -228
  585. package/src/mixins/collection.mixin.js +0 -170
  586. package/src/mixins/default_controls.js +0 -114
  587. package/src/mixins/itext.svg_export.js +0 -241
  588. package/src/mixins/itext_behavior.mixin.js +0 -940
  589. package/src/mixins/itext_click_behavior.mixin.js +0 -278
  590. package/src/mixins/itext_key_behavior.mixin.js +0 -694
  591. package/src/mixins/object.svg_export.js +0 -258
  592. package/src/mixins/object_geometry.mixin.js +0 -683
  593. package/src/mixins/object_interactivity.mixin.js +0 -314
  594. package/src/mixins/object_origin.mixin.js +0 -255
  595. package/src/mixins/object_stacking.mixin.js +0 -80
  596. package/src/mixins/object_straightening.mixin.js +0 -80
  597. package/src/mixins/observable.mixin.js +0 -141
  598. package/src/mixins/shared_methods.mixin.js +0 -94
  599. package/src/mixins/stateful.mixin.js +0 -107
  600. package/src/mixins/text_style.mixin.js +0 -324
  601. package/src/parser.js +0 -1090
  602. package/src/pattern.class.js +0 -189
  603. package/src/point.class.js +0 -337
  604. package/src/shadow.class.js +0 -195
  605. package/src/shapes/active_selection.class.js +0 -155
  606. package/src/shapes/circle.class.js +0 -210
  607. package/src/shapes/ellipse.class.js +0 -181
  608. package/src/shapes/group.class.js +0 -593
  609. package/src/shapes/image.class.js +0 -764
  610. package/src/shapes/itext.class.js +0 -526
  611. package/src/shapes/line.class.js +0 -324
  612. package/src/shapes/object.class.js +0 -2008
  613. package/src/shapes/path.class.js +0 -384
  614. package/src/shapes/polygon.class.js +0 -81
  615. package/src/shapes/polyline.class.js +0 -268
  616. package/src/shapes/rect.class.js +0 -187
  617. package/src/shapes/text.class.js +0 -1696
  618. package/src/shapes/textbox.class.js +0 -461
  619. package/src/shapes/triangle.class.js +0 -93
  620. package/src/static_canvas.class.js +0 -1881
  621. package/src/util/anim_ease.js +0 -398
  622. package/src/util/animate.js +0 -254
  623. package/src/util/animate_color.js +0 -74
  624. package/src/util/dom_event.js +0 -50
  625. package/src/util/dom_misc.js +0 -300
  626. package/src/util/dom_request.js +0 -54
  627. package/src/util/dom_style.js +0 -70
  628. package/src/util/lang_array.js +0 -94
  629. package/src/util/lang_class.js +0 -115
  630. package/src/util/lang_object.js +0 -75
  631. package/src/util/lang_string.js +0 -110
  632. package/src/util/misc.js +0 -1330
  633. package/src/util/named_accessors.mixin.js +0 -428
  634. package/src/util/path.js +0 -829
@@ -0,0 +1,1891 @@
1
+ import { cache } from '../../cache';
2
+ import { DEFAULT_SVG_FONT_SIZE } from '../../constants';
3
+ import type { ObjectEvents } from '../../EventTypeDefs';
4
+ import type {
5
+ CompleteTextStyleDeclaration,
6
+ TextStyle,
7
+ TextStyleDeclaration,
8
+ } from './StyledText';
9
+ import { StyledText } from './StyledText';
10
+ import { SHARED_ATTRIBUTES } from '../../parser/attributes';
11
+ import { parseAttributes } from '../../parser/parseAttributes';
12
+ import type { XY } from '../../Point';
13
+ import type {
14
+ TCacheCanvasDimensions,
15
+ TClassProperties,
16
+ TFiller,
17
+ } from '../../typedefs';
18
+ import { classRegistry } from '../../ClassRegistry';
19
+ import { graphemeSplit } from '../../util/lang_string';
20
+ import { createCanvasElement } from '../../util/misc/dom';
21
+ import {
22
+ hasStyleChanged,
23
+ stylesFromArray,
24
+ stylesToArray,
25
+ } from '../../util/misc/textStyles';
26
+ import { getPathSegmentsInfo, getPointOnPath } from '../../util/path';
27
+ import { cacheProperties } from '../Object/FabricObject';
28
+ import type { Path } from '../Path';
29
+ import { TextSVGExportMixin } from './TextSVGExportMixin';
30
+ import { applyMixins } from '../../util/applyMixins';
31
+ import type {
32
+ FabricObjectProps,
33
+ SerializedObjectProps,
34
+ TProps,
35
+ } from '../Object/types';
36
+ import type { StylePropertiesType } from './constants';
37
+ import {
38
+ additionalProps,
39
+ textDefaultValues,
40
+ textLayoutProperties,
41
+ JUSTIFY,
42
+ JUSTIFY_CENTER,
43
+ JUSTIFY_LEFT,
44
+ JUSTIFY_RIGHT,
45
+ } from './constants';
46
+ import { CENTER, LEFT, RIGHT, TOP, BOTTOM } from '../../constants';
47
+ import { isFiller } from '../../util/typeAssertions';
48
+ import type { Gradient, Pattern } from 'fabric';
49
+
50
+ let measuringContext: CanvasRenderingContext2D | null;
51
+
52
+ /**
53
+ * Return a context for measurement of text string.
54
+ * if created it gets stored for reuse
55
+ */
56
+ function getMeasuringContext() {
57
+ if (!measuringContext) {
58
+ measuringContext = createCanvasElement().getContext('2d');
59
+ }
60
+ return measuringContext;
61
+ }
62
+
63
+ type TPathSide = 'left' | 'right';
64
+
65
+ type TPathAlign = 'baseline' | 'center' | 'ascender' | 'descender';
66
+
67
+ /**
68
+ * Measure and return the info of a single grapheme.
69
+ * needs the the info of previous graphemes already filled
70
+ * Override to customize measuring
71
+ */
72
+ export type GraphemeBBox = {
73
+ width: number;
74
+ height: number;
75
+ kernedWidth: number;
76
+ left: number;
77
+ deltaY: number;
78
+ renderLeft?: number;
79
+ renderTop?: number;
80
+ angle?: number;
81
+ };
82
+
83
+ // @TODO this is not complete
84
+ interface UniqueTextProps {
85
+ charSpacing: number;
86
+ lineHeight: number;
87
+ fontSize: number;
88
+ fontWeight: string;
89
+ fontFamily: string;
90
+ fontStyle: string;
91
+ pathSide: TPathSide;
92
+ pathAlign: TPathAlign;
93
+ underline: boolean;
94
+ overline: boolean;
95
+ linethrough: boolean;
96
+ textAlign: string;
97
+ direction: CanvasDirection;
98
+ path?: Path;
99
+ }
100
+
101
+ export interface SerializedTextProps
102
+ extends SerializedObjectProps,
103
+ UniqueTextProps {}
104
+
105
+ export interface TextProps extends FabricObjectProps, UniqueTextProps {}
106
+
107
+ /**
108
+ * Text class
109
+ * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#text}
110
+ */
111
+ export class Text<
112
+ Props extends TProps<TextProps> = Partial<TextProps>,
113
+ SProps extends SerializedTextProps = SerializedTextProps,
114
+ EventSpec extends ObjectEvents = ObjectEvents
115
+ >
116
+ extends StyledText<Props, SProps, EventSpec>
117
+ implements UniqueTextProps
118
+ {
119
+ /**
120
+ * Properties that requires a text layout recalculation when changed
121
+ * @type string[]
122
+ * @protected
123
+ */
124
+ static textLayoutProperties: string[] = textLayoutProperties;
125
+
126
+ /**
127
+ * @private
128
+ */
129
+ declare _reNewline: RegExp;
130
+
131
+ /**
132
+ * Use this regular expression to filter for whitespaces that is not a new line.
133
+ * Mostly used when text is 'justify' aligned.
134
+ * @private
135
+ */
136
+ declare _reSpacesAndTabs: RegExp;
137
+
138
+ /**
139
+ * Use this regular expression to filter for whitespace that is not a new line.
140
+ * Mostly used when text is 'justify' aligned.
141
+ * @private
142
+ */
143
+ declare _reSpaceAndTab: RegExp;
144
+
145
+ /**
146
+ * Use this regular expression to filter consecutive groups of non spaces.
147
+ * Mostly used when text is 'justify' aligned.
148
+ * @private
149
+ */
150
+ declare _reWords: RegExp;
151
+
152
+ declare text: string;
153
+
154
+ /**
155
+ * Font size (in pixels)
156
+ * @type Number
157
+ * @default
158
+ */
159
+ declare fontSize: number;
160
+
161
+ /**
162
+ * Font weight (e.g. bold, normal, 400, 600, 800)
163
+ * @type {(Number|String)}
164
+ * @default
165
+ */
166
+ declare fontWeight: string;
167
+
168
+ /**
169
+ * Font family
170
+ * @type String
171
+ * @default
172
+ */
173
+ declare fontFamily: string;
174
+
175
+ /**
176
+ * Text decoration underline.
177
+ * @type Boolean
178
+ * @default
179
+ */
180
+ declare underline: boolean;
181
+
182
+ /**
183
+ * Text decoration overline.
184
+ * @type Boolean
185
+ * @default
186
+ */
187
+ declare overline: boolean;
188
+
189
+ /**
190
+ * Text decoration linethrough.
191
+ * @type Boolean
192
+ * @default
193
+ */
194
+ declare linethrough: boolean;
195
+
196
+ /**
197
+ * Text alignment. Possible values: "left", "center", "right", "justify",
198
+ * "justify-left", "justify-center" or "justify-right".
199
+ * @type String
200
+ * @default
201
+ */
202
+ declare textAlign: string;
203
+
204
+ /**
205
+ * Font style . Possible values: "", "normal", "italic" or "oblique".
206
+ * @type String
207
+ * @default
208
+ */
209
+ declare fontStyle: string;
210
+
211
+ /**
212
+ * Line height
213
+ * @type Number
214
+ * @default
215
+ */
216
+ declare lineHeight: number;
217
+
218
+ /**
219
+ * Superscript schema object (minimum overlap)
220
+ */
221
+ declare superscript: {
222
+ /**
223
+ * fontSize factor
224
+ * @default 0.6
225
+ */
226
+ size: number;
227
+ /**
228
+ * baseline-shift factor (upwards)
229
+ * @default -0.35
230
+ */
231
+ baseline: number;
232
+ };
233
+
234
+ /**
235
+ * Subscript schema object (minimum overlap)
236
+ */
237
+ declare subscript: {
238
+ /**
239
+ * fontSize factor
240
+ * @default 0.6
241
+ */
242
+ size: number;
243
+ /**
244
+ * baseline-shift factor (downwards)
245
+ * @default 0.11
246
+ */
247
+ baseline: number;
248
+ };
249
+
250
+ /**
251
+ * Background color of text lines
252
+ * @type String
253
+ * @default
254
+ */
255
+ declare textBackgroundColor: string;
256
+
257
+ declare styles: TextStyle;
258
+
259
+ /**
260
+ * Path that the text should follow.
261
+ * since 4.6.0 the path will be drawn automatically.
262
+ * if you want to make the path visible, give it a stroke and strokeWidth or fill value
263
+ * if you want it to be hidden, assign visible = false to the path.
264
+ * This feature is in BETA, and SVG import/export is not yet supported.
265
+ * @type Path
266
+ * @example
267
+ * const textPath = new Text('Text on a path', {
268
+ * top: 150,
269
+ * left: 150,
270
+ * textAlign: 'center',
271
+ * charSpacing: -50,
272
+ * path: new Path('M 0 0 C 50 -100 150 -100 200 0', {
273
+ * strokeWidth: 1,
274
+ * visible: false
275
+ * }),
276
+ * pathSide: 'left',
277
+ * pathStartOffset: 0
278
+ * });
279
+ * @default
280
+ */
281
+ declare path?: Path;
282
+
283
+ /**
284
+ * Offset amount for text path starting position
285
+ * Only used when text has a path
286
+ * @type Number
287
+ * @default
288
+ */
289
+ declare pathStartOffset: number;
290
+
291
+ /**
292
+ * Which side of the path the text should be drawn on.
293
+ * Only used when text has a path
294
+ * @type {TPathSide} 'left|right'
295
+ * @default
296
+ */
297
+ declare pathSide: TPathSide;
298
+
299
+ /**
300
+ * How text is aligned to the path. This property determines
301
+ * the perpendicular position of each character relative to the path.
302
+ * (one of "baseline", "center", "ascender", "descender")
303
+ * This feature is in BETA, and its behavior may change
304
+ * @type TPathAlign
305
+ * @default
306
+ */
307
+ declare pathAlign: TPathAlign;
308
+
309
+ /**
310
+ * @private
311
+ */
312
+ declare _fontSizeFraction: number;
313
+
314
+ /**
315
+ * @private
316
+ */
317
+ declare offsets: { underline: number; linethrough: number; overline: number };
318
+
319
+ /**
320
+ * Text Line proportion to font Size (in pixels)
321
+ * @type Number
322
+ * @default
323
+ */
324
+ declare _fontSizeMult: number;
325
+
326
+ /**
327
+ * additional space between characters
328
+ * expressed in thousands of em unit
329
+ * @type Number
330
+ * @default
331
+ */
332
+ declare charSpacing: number;
333
+
334
+ /**
335
+ * Baseline shift, styles only, keep at 0 for the main text object
336
+ * @type {Number}
337
+ * @default
338
+ */
339
+ declare deltaY: number;
340
+
341
+ /**
342
+ * WARNING: EXPERIMENTAL. NOT SUPPORTED YET
343
+ * determine the direction of the text.
344
+ * This has to be set manually together with textAlign and originX for proper
345
+ * experience.
346
+ * some interesting link for the future
347
+ * https://www.w3.org/International/questions/qa-bidi-unicode-controls
348
+ * @since 4.5.0
349
+ * @type {CanvasDirection} 'ltr|rtl'
350
+ * @default
351
+ */
352
+ declare direction: CanvasDirection;
353
+
354
+ /**
355
+ * contains characters bounding boxes
356
+ */
357
+ protected __charBounds: GraphemeBBox[][] = [];
358
+
359
+ /**
360
+ * use this size when measuring text. To avoid IE11 rounding errors
361
+ * @type {Number}
362
+ * @default
363
+ * @readonly
364
+ * @private
365
+ */
366
+ declare CACHE_FONT_SIZE: number;
367
+
368
+ /**
369
+ * contains the min text width to avoid getting 0
370
+ * @type {Number}
371
+ * @default
372
+ */
373
+ declare MIN_TEXT_WIDTH: number;
374
+
375
+ /**
376
+ * contains the the text of the object, divided in lines as they are displayed
377
+ * on screen. Wrapping will divide the text independently of line breaks
378
+ * @type {string[]}
379
+ * @default
380
+ */
381
+ declare textLines: string[];
382
+
383
+ /**
384
+ * same as textlines, but each line is an array of graphemes as split by splitByGrapheme
385
+ * @type {string[]}
386
+ * @default
387
+ */
388
+ declare _textLines: string[][];
389
+
390
+ declare _unwrappedTextLines: string[][];
391
+ declare _text: string[];
392
+ declare cursorWidth: number;
393
+ declare __lineHeights: number[];
394
+ declare __lineWidths: number[];
395
+ declare initialized?: true;
396
+
397
+ static cacheProperties = [...cacheProperties, ...additionalProps];
398
+
399
+ static ownDefaults: Record<string, any> = textDefaultValues;
400
+
401
+ static type = 'Text';
402
+
403
+ static getDefaults() {
404
+ return { ...super.getDefaults(), ...Text.ownDefaults };
405
+ }
406
+
407
+ constructor(text: string, options: any) {
408
+ super({ ...options, text, styles: options?.styles || {} });
409
+ this.initialized = true;
410
+ if (this.path) {
411
+ this.setPathInfo();
412
+ }
413
+ this.initDimensions();
414
+ this.setCoords();
415
+ }
416
+
417
+ /**
418
+ * If text has a path, it will add the extra information needed
419
+ * for path and text calculations
420
+ */
421
+ setPathInfo() {
422
+ const path = this.path;
423
+ if (path) {
424
+ path.segmentsInfo = getPathSegmentsInfo(path.path);
425
+ }
426
+ }
427
+
428
+ /**
429
+ * @private
430
+ * Divides text into lines of text and lines of graphemes.
431
+ */
432
+ _splitText() {
433
+ const newLines = this._splitTextIntoLines(this.text);
434
+ this.textLines = newLines.lines;
435
+ this._textLines = newLines.graphemeLines;
436
+ this._unwrappedTextLines = newLines._unwrappedLines;
437
+ this._text = newLines.graphemeText;
438
+ return newLines;
439
+ }
440
+
441
+ /**
442
+ * Initialize or update text dimensions.
443
+ * Updates this.width and this.height with the proper values.
444
+ * Does not return dimensions.
445
+ */
446
+ initDimensions() {
447
+ this._splitText();
448
+ this._clearCache();
449
+ this.dirty = true;
450
+ if (this.path) {
451
+ this.width = this.path.width;
452
+ this.height = this.path.height;
453
+ } else {
454
+ this.width =
455
+ this.calcTextWidth() || this.cursorWidth || this.MIN_TEXT_WIDTH;
456
+ this.height = this.calcTextHeight();
457
+ }
458
+ if (this.textAlign.includes(JUSTIFY)) {
459
+ // once text is measured we need to make space fatter to make justified text.
460
+ this.enlargeSpaces();
461
+ }
462
+ }
463
+
464
+ /**
465
+ * Enlarge space boxes and shift the others
466
+ */
467
+ enlargeSpaces() {
468
+ let diffSpace,
469
+ currentLineWidth,
470
+ numberOfSpaces,
471
+ accumulatedSpace,
472
+ line,
473
+ charBound,
474
+ spaces;
475
+ for (let i = 0, len = this._textLines.length; i < len; i++) {
476
+ if (
477
+ this.textAlign !== JUSTIFY &&
478
+ (i === len - 1 || this.isEndOfWrapping(i))
479
+ ) {
480
+ continue;
481
+ }
482
+ accumulatedSpace = 0;
483
+ line = this._textLines[i];
484
+ currentLineWidth = this.getLineWidth(i);
485
+ if (
486
+ currentLineWidth < this.width &&
487
+ (spaces = this.textLines[i].match(this._reSpacesAndTabs))
488
+ ) {
489
+ numberOfSpaces = spaces.length;
490
+ diffSpace = (this.width - currentLineWidth) / numberOfSpaces;
491
+ for (let j = 0; j <= line.length; j++) {
492
+ charBound = this.__charBounds[i][j];
493
+ if (this._reSpaceAndTab.test(line[j])) {
494
+ charBound.width += diffSpace;
495
+ charBound.kernedWidth += diffSpace;
496
+ charBound.left += accumulatedSpace;
497
+ accumulatedSpace += diffSpace;
498
+ } else {
499
+ charBound.left += accumulatedSpace;
500
+ }
501
+ }
502
+ }
503
+ }
504
+ }
505
+
506
+ /**
507
+ * Detect if the text line is ended with an hard break
508
+ * text and itext do not have wrapping, return false
509
+ * @return {Boolean}
510
+ */
511
+ isEndOfWrapping(lineIndex: number): boolean {
512
+ return lineIndex === this._textLines.length - 1;
513
+ }
514
+
515
+ /**
516
+ * Detect if a line has a linebreak and so we need to account for it when moving
517
+ * and counting style.
518
+ * It return always for text and Itext.
519
+ * @return Number
520
+ */
521
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
522
+ missingNewlineOffset(lineIndex: number) {
523
+ return 1;
524
+ }
525
+
526
+ /**
527
+ * Returns 2d representation (lineIndex and charIndex) of cursor
528
+ * @param {Number} selectionStart
529
+ * @param {Boolean} [skipWrapping] consider the location for unwrapped lines. useful to manage styles.
530
+ */
531
+ get2DCursorLocation(selectionStart: number, skipWrapping?: boolean) {
532
+ const lines = skipWrapping ? this._unwrappedTextLines : this._textLines;
533
+ let i: number;
534
+ for (i = 0; i < lines.length; i++) {
535
+ if (selectionStart <= lines[i].length) {
536
+ return {
537
+ lineIndex: i,
538
+ charIndex: selectionStart,
539
+ };
540
+ }
541
+ selectionStart -= lines[i].length + this.missingNewlineOffset(i);
542
+ }
543
+ return {
544
+ lineIndex: i - 1,
545
+ charIndex:
546
+ lines[i - 1].length < selectionStart
547
+ ? lines[i - 1].length
548
+ : selectionStart,
549
+ };
550
+ }
551
+
552
+ /**
553
+ * Returns string representation of an instance
554
+ * @return {String} String representation of text object
555
+ */
556
+ toString(): string {
557
+ return `#<Text (${this.complexity()}): { "text": "${
558
+ this.text
559
+ }", "fontFamily": "${this.fontFamily}" }>`;
560
+ }
561
+
562
+ /**
563
+ * Return the dimension and the zoom level needed to create a cache canvas
564
+ * big enough to host the object to be cached.
565
+ * @private
566
+ * @param {Object} dim.x width of object to be cached
567
+ * @param {Object} dim.y height of object to be cached
568
+ * @return {Object}.width width of canvas
569
+ * @return {Object}.height height of canvas
570
+ * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache
571
+ * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache
572
+ */
573
+ _getCacheCanvasDimensions(): TCacheCanvasDimensions {
574
+ const dims = super._getCacheCanvasDimensions();
575
+ const fontSize = this.fontSize;
576
+ dims.width += fontSize * dims.zoomX;
577
+ dims.height += fontSize * dims.zoomY;
578
+ return dims;
579
+ }
580
+
581
+ /**
582
+ * @private
583
+ * @param {CanvasRenderingContext2D} ctx Context to render on
584
+ */
585
+ _render(ctx: CanvasRenderingContext2D) {
586
+ const path = this.path;
587
+ path && !path.isNotVisible() && path._render(ctx);
588
+ this._setTextStyles(ctx);
589
+ this._renderTextLinesBackground(ctx);
590
+ this._renderTextDecoration(ctx, 'underline');
591
+ this._renderText(ctx);
592
+ this._renderTextDecoration(ctx, 'overline');
593
+ this._renderTextDecoration(ctx, 'linethrough');
594
+ }
595
+
596
+ /**
597
+ * @private
598
+ * @param {CanvasRenderingContext2D} ctx Context to render on
599
+ */
600
+ _renderText(ctx: CanvasRenderingContext2D) {
601
+ if (this.paintFirst === 'stroke') {
602
+ this._renderTextStroke(ctx);
603
+ this._renderTextFill(ctx);
604
+ } else {
605
+ this._renderTextFill(ctx);
606
+ this._renderTextStroke(ctx);
607
+ }
608
+ }
609
+
610
+ /**
611
+ * Set the font parameter of the context with the object properties or with charStyle
612
+ * @private
613
+ * @param {CanvasRenderingContext2D} ctx Context to render on
614
+ * @param {Object} [charStyle] object with font style properties
615
+ * @param {String} [charStyle.fontFamily] Font Family
616
+ * @param {Number} [charStyle.fontSize] Font size in pixels. ( without px suffix )
617
+ * @param {String} [charStyle.fontWeight] Font weight
618
+ * @param {String} [charStyle.fontStyle] Font style (italic|normal)
619
+ */
620
+ _setTextStyles(
621
+ ctx: CanvasRenderingContext2D,
622
+ charStyle?: any,
623
+ forMeasuring?: boolean
624
+ ) {
625
+ ctx.textBaseline = 'alphabetic';
626
+ if (this.path) {
627
+ switch (this.pathAlign) {
628
+ case CENTER:
629
+ ctx.textBaseline = 'middle';
630
+ break;
631
+ case 'ascender':
632
+ ctx.textBaseline = TOP;
633
+ break;
634
+ case 'descender':
635
+ ctx.textBaseline = BOTTOM;
636
+ break;
637
+ }
638
+ }
639
+ ctx.font = this._getFontDeclaration(charStyle, forMeasuring);
640
+ }
641
+
642
+ /**
643
+ * calculate and return the text Width measuring each line.
644
+ * @private
645
+ * @param {CanvasRenderingContext2D} ctx Context to render on
646
+ * @return {Number} Maximum width of Text object
647
+ */
648
+ calcTextWidth(): number {
649
+ let maxWidth = this.getLineWidth(0);
650
+
651
+ for (let i = 1, len = this._textLines.length; i < len; i++) {
652
+ const currentLineWidth = this.getLineWidth(i);
653
+ if (currentLineWidth > maxWidth) {
654
+ maxWidth = currentLineWidth;
655
+ }
656
+ }
657
+ return maxWidth;
658
+ }
659
+
660
+ /**
661
+ * @private
662
+ * @param {String} method Method name ("fillText" or "strokeText")
663
+ * @param {CanvasRenderingContext2D} ctx Context to render on
664
+ * @param {String} line Text to render
665
+ * @param {Number} left Left position of text
666
+ * @param {Number} top Top position of text
667
+ * @param {Number} lineIndex Index of a line in a text
668
+ */
669
+ _renderTextLine(
670
+ method: 'fillText' | 'strokeText',
671
+ ctx: CanvasRenderingContext2D,
672
+ line: string[],
673
+ left: number,
674
+ top: number,
675
+ lineIndex: number
676
+ ) {
677
+ this._renderChars(method, ctx, line, left, top, lineIndex);
678
+ }
679
+
680
+ /**
681
+ * Renders the text background for lines, taking care of style
682
+ * @private
683
+ * @param {CanvasRenderingContext2D} ctx Context to render on
684
+ */
685
+ _renderTextLinesBackground(ctx: CanvasRenderingContext2D) {
686
+ if (!this.textBackgroundColor && !this.styleHas('textBackgroundColor')) {
687
+ return;
688
+ }
689
+ const originalFill = ctx.fillStyle,
690
+ leftOffset = this._getLeftOffset();
691
+ let lineTopOffset = this._getTopOffset();
692
+
693
+ for (let i = 0, len = this._textLines.length; i < len; i++) {
694
+ const heightOfLine = this.getHeightOfLine(i);
695
+ if (
696
+ !this.textBackgroundColor &&
697
+ !this.styleHas('textBackgroundColor', i)
698
+ ) {
699
+ lineTopOffset += heightOfLine;
700
+ continue;
701
+ }
702
+ const jlen = this._textLines[i].length;
703
+ const lineLeftOffset = this._getLineLeftOffset(i);
704
+ let boxWidth = 0;
705
+ let boxStart = 0;
706
+ let drawStart;
707
+ let currentColor;
708
+ let lastColor = this.getValueOfPropertyAt(i, 0, 'textBackgroundColor');
709
+ for (let j = 0; j < jlen; j++) {
710
+ // at this point charbox are either standard or full with pathInfo if there is a path.
711
+ const charBox = this.__charBounds[i][j] as Required<GraphemeBBox>;
712
+ currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor');
713
+ if (this.path) {
714
+ ctx.save();
715
+ ctx.translate(charBox.renderLeft, charBox.renderTop);
716
+ ctx.rotate(charBox.angle);
717
+ ctx.fillStyle = currentColor;
718
+ currentColor &&
719
+ ctx.fillRect(
720
+ -charBox.width / 2,
721
+ (-heightOfLine / this.lineHeight) * (1 - this._fontSizeFraction),
722
+ charBox.width,
723
+ heightOfLine / this.lineHeight
724
+ );
725
+ ctx.restore();
726
+ } else if (currentColor !== lastColor) {
727
+ drawStart = leftOffset + lineLeftOffset + boxStart;
728
+ if (this.direction === 'rtl') {
729
+ drawStart = this.width - drawStart - boxWidth;
730
+ }
731
+ ctx.fillStyle = lastColor;
732
+ lastColor &&
733
+ ctx.fillRect(
734
+ drawStart,
735
+ lineTopOffset,
736
+ boxWidth,
737
+ heightOfLine / this.lineHeight
738
+ );
739
+ boxStart = charBox.left;
740
+ boxWidth = charBox.width;
741
+ lastColor = currentColor;
742
+ } else {
743
+ boxWidth += charBox.kernedWidth;
744
+ }
745
+ }
746
+ if (currentColor && !this.path) {
747
+ drawStart = leftOffset + lineLeftOffset + boxStart;
748
+ if (this.direction === 'rtl') {
749
+ drawStart = this.width - drawStart - boxWidth;
750
+ }
751
+ ctx.fillStyle = currentColor;
752
+ ctx.fillRect(
753
+ drawStart,
754
+ lineTopOffset,
755
+ boxWidth,
756
+ heightOfLine / this.lineHeight
757
+ );
758
+ }
759
+ lineTopOffset += heightOfLine;
760
+ }
761
+ ctx.fillStyle = originalFill;
762
+ // if there is text background color no
763
+ // other shadows should be casted
764
+ this._removeShadow(ctx);
765
+ }
766
+
767
+ /**
768
+ * measure and return the width of a single character.
769
+ * possibly overridden to accommodate different measure logic or
770
+ * to hook some external lib for character measurement
771
+ * @private
772
+ * @param {String} _char, char to be measured
773
+ * @param {Object} charStyle style of char to be measured
774
+ * @param {String} [previousChar] previous char
775
+ * @param {Object} [prevCharStyle] style of previous char
776
+ */
777
+ _measureChar(
778
+ _char: string,
779
+ charStyle: CompleteTextStyleDeclaration,
780
+ previousChar: string | undefined,
781
+ prevCharStyle: CompleteTextStyleDeclaration | Record<string, never>
782
+ ) {
783
+ const fontCache = cache.getFontCache(charStyle),
784
+ fontDeclaration = this._getFontDeclaration(charStyle),
785
+ previousFontDeclaration = this._getFontDeclaration(prevCharStyle),
786
+ couple = previousChar + _char,
787
+ stylesAreEqual = fontDeclaration === previousFontDeclaration,
788
+ fontMultiplier = charStyle.fontSize / this.CACHE_FONT_SIZE;
789
+ let width: number | undefined,
790
+ coupleWidth: number | undefined,
791
+ previousWidth: number | undefined,
792
+ kernedWidth: number | undefined;
793
+
794
+ if (previousChar && fontCache[previousChar] !== undefined) {
795
+ previousWidth = fontCache[previousChar];
796
+ }
797
+ if (fontCache[_char] !== undefined) {
798
+ kernedWidth = width = fontCache[_char];
799
+ }
800
+ if (stylesAreEqual && fontCache[couple] !== undefined) {
801
+ coupleWidth = fontCache[couple];
802
+ kernedWidth = coupleWidth - previousWidth!;
803
+ }
804
+ if (
805
+ width === undefined ||
806
+ previousWidth === undefined ||
807
+ coupleWidth === undefined
808
+ ) {
809
+ const ctx = getMeasuringContext()!;
810
+ // send a TRUE to specify measuring font size CACHE_FONT_SIZE
811
+ this._setTextStyles(ctx, charStyle, true);
812
+ if (width === undefined) {
813
+ kernedWidth = width = ctx.measureText(_char).width;
814
+ fontCache[_char] = width;
815
+ }
816
+ if (previousWidth === undefined && stylesAreEqual && previousChar) {
817
+ previousWidth = ctx.measureText(previousChar).width;
818
+ fontCache[previousChar] = previousWidth;
819
+ }
820
+ if (stylesAreEqual && coupleWidth === undefined) {
821
+ // we can measure the kerning couple and subtract the width of the previous character
822
+ coupleWidth = ctx.measureText(couple).width;
823
+ fontCache[couple] = coupleWidth;
824
+ // safe to use the non-null since if undefined we defined it before.
825
+ kernedWidth = coupleWidth - previousWidth!;
826
+ }
827
+ }
828
+ return {
829
+ width: width * fontMultiplier,
830
+ kernedWidth: kernedWidth! * fontMultiplier,
831
+ };
832
+ }
833
+
834
+ /**
835
+ * Computes height of character at given position
836
+ * @param {Number} line the line index number
837
+ * @param {Number} _char the character index number
838
+ * @return {Number} fontSize of the character
839
+ */
840
+ getHeightOfChar(line: number, _char: number): number {
841
+ return this.getValueOfPropertyAt(line, _char, 'fontSize');
842
+ }
843
+
844
+ /**
845
+ * measure a text line measuring all characters.
846
+ * @param {Number} lineIndex line number
847
+ */
848
+ measureLine(lineIndex: number) {
849
+ const lineInfo = this._measureLine(lineIndex);
850
+ if (this.charSpacing !== 0) {
851
+ lineInfo.width -= this._getWidthOfCharSpacing();
852
+ }
853
+ if (lineInfo.width < 0) {
854
+ lineInfo.width = 0;
855
+ }
856
+ return lineInfo;
857
+ }
858
+
859
+ /**
860
+ * measure every grapheme of a line, populating __charBounds
861
+ * @param {Number} lineIndex
862
+ * @return {Object} object.width total width of characters
863
+ * @return {Object} object.numOfSpaces length of chars that match this._reSpacesAndTabs
864
+ */
865
+ _measureLine(lineIndex: number) {
866
+ let width = 0,
867
+ prevGrapheme: string | undefined,
868
+ graphemeInfo: GraphemeBBox | undefined;
869
+
870
+ const reverse = this.pathSide === RIGHT,
871
+ path = this.path,
872
+ line = this._textLines[lineIndex],
873
+ llength = line.length,
874
+ lineBounds = new Array<GraphemeBBox>(llength);
875
+
876
+ this.__charBounds[lineIndex] = lineBounds;
877
+ for (let i = 0; i < llength; i++) {
878
+ const grapheme = line[i];
879
+ graphemeInfo = this._getGraphemeBox(grapheme, lineIndex, i, prevGrapheme);
880
+ lineBounds[i] = graphemeInfo;
881
+ width += graphemeInfo.kernedWidth;
882
+ prevGrapheme = grapheme;
883
+ }
884
+ // this latest bound box represent the last character of the line
885
+ // to simplify cursor handling in interactive mode.
886
+ lineBounds[llength] = {
887
+ left: graphemeInfo ? graphemeInfo.left + graphemeInfo.width : 0,
888
+ width: 0,
889
+ kernedWidth: 0,
890
+ height: this.fontSize,
891
+ deltaY: 0,
892
+ } as GraphemeBBox;
893
+ if (path && path.segmentsInfo) {
894
+ let positionInPath = 0;
895
+ const totalPathLength =
896
+ path.segmentsInfo[path.segmentsInfo.length - 1].length;
897
+ const startingPoint = getPointOnPath(path.path, 0, path.segmentsInfo)!;
898
+ startingPoint.x += path.pathOffset.x;
899
+ startingPoint.y += path.pathOffset.y;
900
+ switch (this.textAlign) {
901
+ case LEFT:
902
+ positionInPath = reverse ? totalPathLength - width : 0;
903
+ break;
904
+ case CENTER:
905
+ positionInPath = (totalPathLength - width) / 2;
906
+ break;
907
+ case RIGHT:
908
+ positionInPath = reverse ? 0 : totalPathLength - width;
909
+ break;
910
+ //todo - add support for justify
911
+ }
912
+ positionInPath += this.pathStartOffset * (reverse ? -1 : 1);
913
+ for (
914
+ let i = reverse ? llength - 1 : 0;
915
+ reverse ? i >= 0 : i < llength;
916
+ reverse ? i-- : i++
917
+ ) {
918
+ graphemeInfo = lineBounds[i];
919
+ if (positionInPath > totalPathLength) {
920
+ positionInPath %= totalPathLength;
921
+ } else if (positionInPath < 0) {
922
+ positionInPath += totalPathLength;
923
+ }
924
+ // it would probably much faster to send all the grapheme position for a line
925
+ // and calculate path position/angle at once.
926
+ this._setGraphemeOnPath(positionInPath, graphemeInfo, startingPoint!);
927
+ positionInPath += graphemeInfo.kernedWidth;
928
+ }
929
+ }
930
+ return { width: width, numOfSpaces: 0 };
931
+ }
932
+
933
+ /**
934
+ * Calculate the angle and the left,top position of the char that follow a path.
935
+ * It appends it to graphemeInfo to be reused later at rendering
936
+ * @private
937
+ * @param {Number} positionInPath to be measured
938
+ * @param {GraphemeBBox} graphemeInfo current grapheme box information
939
+ * @param {Object} startingPoint position of the point
940
+ */
941
+ _setGraphemeOnPath(
942
+ positionInPath: number,
943
+ graphemeInfo: GraphemeBBox,
944
+ startingPoint: XY
945
+ ) {
946
+ const centerPosition = positionInPath + graphemeInfo.kernedWidth / 2,
947
+ path = this.path!;
948
+
949
+ // we are at currentPositionOnPath. we want to know what point on the path is.
950
+ const info = getPointOnPath(path.path, centerPosition, path.segmentsInfo)!;
951
+ graphemeInfo.renderLeft = info.x - startingPoint.x;
952
+ graphemeInfo.renderTop = info.y - startingPoint.y;
953
+ graphemeInfo.angle = info.angle + (this.pathSide === RIGHT ? Math.PI : 0);
954
+ }
955
+
956
+ /**
957
+ *
958
+ * @param {String} grapheme to be measured
959
+ * @param {Number} lineIndex index of the line where the char is
960
+ * @param {Number} charIndex position in the line
961
+ * @param {String} [prevGrapheme] character preceding the one to be measured
962
+ * @returns {GraphemeBBox} grapheme bbox
963
+ */
964
+ _getGraphemeBox(
965
+ grapheme: string,
966
+ lineIndex: number,
967
+ charIndex: number,
968
+ prevGrapheme?: string,
969
+ skipLeft?: boolean
970
+ ): GraphemeBBox {
971
+ const style = this.getCompleteStyleDeclaration(lineIndex, charIndex),
972
+ prevStyle = prevGrapheme
973
+ ? this.getCompleteStyleDeclaration(lineIndex, charIndex - 1)
974
+ : {},
975
+ info = this._measureChar(grapheme, style, prevGrapheme, prevStyle);
976
+ let kernedWidth = info.kernedWidth,
977
+ width = info.width,
978
+ charSpacing;
979
+
980
+ if (this.charSpacing !== 0) {
981
+ charSpacing = this._getWidthOfCharSpacing();
982
+ width += charSpacing;
983
+ kernedWidth += charSpacing;
984
+ }
985
+
986
+ const box: GraphemeBBox = {
987
+ width,
988
+ left: 0,
989
+ height: style.fontSize,
990
+ kernedWidth,
991
+ deltaY: style.deltaY,
992
+ };
993
+ if (charIndex > 0 && !skipLeft) {
994
+ const previousBox = this.__charBounds[lineIndex][charIndex - 1];
995
+ box.left =
996
+ previousBox.left + previousBox.width + info.kernedWidth - info.width;
997
+ }
998
+ return box;
999
+ }
1000
+
1001
+ /**
1002
+ * Calculate height of line at 'lineIndex'
1003
+ * @param {Number} lineIndex index of line to calculate
1004
+ * @return {Number}
1005
+ */
1006
+ getHeightOfLine(lineIndex: number): number {
1007
+ if (this.__lineHeights[lineIndex]) {
1008
+ return this.__lineHeights[lineIndex];
1009
+ }
1010
+
1011
+ // char 0 is measured before the line cycle because it needs to char
1012
+ // emptylines
1013
+ let maxHeight = this.getHeightOfChar(lineIndex, 0);
1014
+ for (let i = 1, len = this._textLines[lineIndex].length; i < len; i++) {
1015
+ maxHeight = Math.max(this.getHeightOfChar(lineIndex, i), maxHeight);
1016
+ }
1017
+
1018
+ return (this.__lineHeights[lineIndex] =
1019
+ maxHeight * this.lineHeight * this._fontSizeMult);
1020
+ }
1021
+
1022
+ /**
1023
+ * Calculate text box height
1024
+ */
1025
+ calcTextHeight() {
1026
+ let lineHeight,
1027
+ height = 0;
1028
+ for (let i = 0, len = this._textLines.length; i < len; i++) {
1029
+ lineHeight = this.getHeightOfLine(i);
1030
+ height += i === len - 1 ? lineHeight / this.lineHeight : lineHeight;
1031
+ }
1032
+ return height;
1033
+ }
1034
+
1035
+ /**
1036
+ * @private
1037
+ * @return {Number} Left offset
1038
+ */
1039
+ _getLeftOffset(): number {
1040
+ return this.direction === 'ltr' ? -this.width / 2 : this.width / 2;
1041
+ }
1042
+
1043
+ /**
1044
+ * @private
1045
+ * @return {Number} Top offset
1046
+ */
1047
+ _getTopOffset(): number {
1048
+ return -this.height / 2;
1049
+ }
1050
+
1051
+ /**
1052
+ * @private
1053
+ * @param {CanvasRenderingContext2D} ctx Context to render on
1054
+ * @param {String} method Method name ("fillText" or "strokeText")
1055
+ */
1056
+ _renderTextCommon(
1057
+ ctx: CanvasRenderingContext2D,
1058
+ method: 'fillText' | 'strokeText'
1059
+ ) {
1060
+ ctx.save();
1061
+ let lineHeights = 0;
1062
+ const left = this._getLeftOffset(),
1063
+ top = this._getTopOffset();
1064
+ for (let i = 0, len = this._textLines.length; i < len; i++) {
1065
+ const heightOfLine = this.getHeightOfLine(i),
1066
+ maxHeight = heightOfLine / this.lineHeight,
1067
+ leftOffset = this._getLineLeftOffset(i);
1068
+ this._renderTextLine(
1069
+ method,
1070
+ ctx,
1071
+ this._textLines[i],
1072
+ left + leftOffset,
1073
+ top + lineHeights + maxHeight,
1074
+ i
1075
+ );
1076
+ lineHeights += heightOfLine;
1077
+ }
1078
+ ctx.restore();
1079
+ }
1080
+
1081
+ /**
1082
+ * @private
1083
+ * @param {CanvasRenderingContext2D} ctx Context to render on
1084
+ */
1085
+ _renderTextFill(ctx: CanvasRenderingContext2D) {
1086
+ if (!this.fill && !this.styleHas('fill')) {
1087
+ return;
1088
+ }
1089
+
1090
+ this._renderTextCommon(ctx, 'fillText');
1091
+ }
1092
+
1093
+ /**
1094
+ * @private
1095
+ * @param {CanvasRenderingContext2D} ctx Context to render on
1096
+ */
1097
+ _renderTextStroke(ctx: CanvasRenderingContext2D) {
1098
+ if ((!this.stroke || this.strokeWidth === 0) && this.isEmptyStyles()) {
1099
+ return;
1100
+ }
1101
+
1102
+ if (this.shadow && !this.shadow.affectStroke) {
1103
+ this._removeShadow(ctx);
1104
+ }
1105
+
1106
+ ctx.save();
1107
+ this._setLineDash(ctx, this.strokeDashArray);
1108
+ ctx.beginPath();
1109
+ this._renderTextCommon(ctx, 'strokeText');
1110
+ ctx.closePath();
1111
+ ctx.restore();
1112
+ }
1113
+
1114
+ /**
1115
+ * @private
1116
+ * @param {String} method fillText or strokeText.
1117
+ * @param {CanvasRenderingContext2D} ctx Context to render on
1118
+ * @param {Array} line Content of the line, splitted in an array by grapheme
1119
+ * @param {Number} left
1120
+ * @param {Number} top
1121
+ * @param {Number} lineIndex
1122
+ */
1123
+ _renderChars(
1124
+ method: 'fillText' | 'strokeText',
1125
+ ctx: CanvasRenderingContext2D,
1126
+ line: Array<any>,
1127
+ left: number,
1128
+ top: number,
1129
+ lineIndex: number
1130
+ ) {
1131
+ const lineHeight = this.getHeightOfLine(lineIndex),
1132
+ isJustify = this.textAlign.includes(JUSTIFY),
1133
+ path = this.path,
1134
+ shortCut =
1135
+ !isJustify &&
1136
+ this.charSpacing === 0 &&
1137
+ this.isEmptyStyles(lineIndex) &&
1138
+ !path,
1139
+ isLtr = this.direction === 'ltr',
1140
+ sign = this.direction === 'ltr' ? 1 : -1,
1141
+ // this was changed in the PR #7674
1142
+ // currentDirection = ctx.canvas.getAttribute('dir');
1143
+ currentDirection = ctx.direction;
1144
+
1145
+ let actualStyle,
1146
+ nextStyle,
1147
+ charsToRender = '',
1148
+ charBox,
1149
+ boxWidth = 0,
1150
+ timeToRender,
1151
+ drawingLeft;
1152
+
1153
+ ctx.save();
1154
+ if (currentDirection !== this.direction) {
1155
+ ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl');
1156
+ ctx.direction = isLtr ? 'ltr' : 'rtl';
1157
+ ctx.textAlign = isLtr ? LEFT : RIGHT;
1158
+ }
1159
+ top -= (lineHeight * this._fontSizeFraction) / this.lineHeight;
1160
+ if (shortCut) {
1161
+ // render all the line in one pass without checking
1162
+ // drawingLeft = isLtr ? left : left - this.getLineWidth(lineIndex);
1163
+ this._renderChar(method, ctx, lineIndex, 0, line.join(''), left, top);
1164
+ ctx.restore();
1165
+ return;
1166
+ }
1167
+ for (let i = 0, len = line.length - 1; i <= len; i++) {
1168
+ timeToRender = i === len || this.charSpacing || path;
1169
+ charsToRender += line[i];
1170
+ charBox = this.__charBounds[lineIndex][i] as Required<GraphemeBBox>;
1171
+ if (boxWidth === 0) {
1172
+ left += sign * (charBox.kernedWidth - charBox.width);
1173
+ boxWidth += charBox.width;
1174
+ } else {
1175
+ boxWidth += charBox.kernedWidth;
1176
+ }
1177
+ if (isJustify && !timeToRender) {
1178
+ if (this._reSpaceAndTab.test(line[i])) {
1179
+ timeToRender = true;
1180
+ }
1181
+ }
1182
+ if (!timeToRender) {
1183
+ // if we have charSpacing, we render char by char
1184
+ actualStyle =
1185
+ actualStyle || this.getCompleteStyleDeclaration(lineIndex, i);
1186
+ nextStyle = this.getCompleteStyleDeclaration(lineIndex, i + 1);
1187
+ timeToRender = hasStyleChanged(actualStyle, nextStyle, false);
1188
+ }
1189
+ if (timeToRender) {
1190
+ if (path) {
1191
+ ctx.save();
1192
+ ctx.translate(charBox.renderLeft, charBox.renderTop);
1193
+ ctx.rotate(charBox.angle);
1194
+ this._renderChar(
1195
+ method,
1196
+ ctx,
1197
+ lineIndex,
1198
+ i,
1199
+ charsToRender,
1200
+ -boxWidth / 2,
1201
+ 0
1202
+ );
1203
+ ctx.restore();
1204
+ } else {
1205
+ drawingLeft = left;
1206
+ this._renderChar(
1207
+ method,
1208
+ ctx,
1209
+ lineIndex,
1210
+ i,
1211
+ charsToRender,
1212
+ drawingLeft,
1213
+ top
1214
+ );
1215
+ }
1216
+ charsToRender = '';
1217
+ actualStyle = nextStyle;
1218
+ left += sign * boxWidth;
1219
+ boxWidth = 0;
1220
+ }
1221
+ }
1222
+ ctx.restore();
1223
+ }
1224
+
1225
+ /**
1226
+ * This function try to patch the missing gradientTransform on canvas gradients.
1227
+ * transforming a context to transform the gradient, is going to transform the stroke too.
1228
+ * we want to transform the gradient but not the stroke operation, so we create
1229
+ * a transformed gradient on a pattern and then we use the pattern instead of the gradient.
1230
+ * this method has drawbacks: is slow, is in low resolution, needs a patch for when the size
1231
+ * is limited.
1232
+ * @private
1233
+ * @param {TFiller} filler a fabric gradient instance
1234
+ * @return {CanvasPattern} a pattern to use as fill/stroke style
1235
+ */
1236
+ _applyPatternGradientTransformText(filler: TFiller) {
1237
+ const pCanvas = createCanvasElement(),
1238
+ // TODO: verify compatibility with strokeUniform
1239
+ width = this.width + this.strokeWidth,
1240
+ height = this.height + this.strokeWidth,
1241
+ pCtx = pCanvas.getContext('2d')!;
1242
+ pCanvas.width = width;
1243
+ pCanvas.height = height;
1244
+ pCtx.beginPath();
1245
+ pCtx.moveTo(0, 0);
1246
+ pCtx.lineTo(width, 0);
1247
+ pCtx.lineTo(width, height);
1248
+ pCtx.lineTo(0, height);
1249
+ pCtx.closePath();
1250
+ pCtx.translate(width / 2, height / 2);
1251
+ pCtx.fillStyle = filler.toLive(pCtx)!;
1252
+ this._applyPatternGradientTransform(pCtx, filler);
1253
+ pCtx.fill();
1254
+ return pCtx.createPattern(pCanvas, 'no-repeat')!;
1255
+ }
1256
+
1257
+ handleFiller<T extends 'fill' | 'stroke'>(
1258
+ ctx: CanvasRenderingContext2D,
1259
+ property: `${T}Style`,
1260
+ filler: TFiller | string
1261
+ ): { offsetX: number; offsetY: number } {
1262
+ let offsetX: number, offsetY: number;
1263
+ if (isFiller(filler)) {
1264
+ if (
1265
+ (filler as Gradient<'linear'>).gradientUnits === 'percentage' ||
1266
+ (filler as Gradient<'linear'>).gradientTransform ||
1267
+ (filler as Pattern).patternTransform
1268
+ ) {
1269
+ // need to transform gradient in a pattern.
1270
+ // this is a slow process. If you are hitting this codepath, and the object
1271
+ // is not using caching, you should consider switching it on.
1272
+ // we need a canvas as big as the current object caching canvas.
1273
+ offsetX = -this.width / 2;
1274
+ offsetY = -this.height / 2;
1275
+ ctx.translate(offsetX, offsetY);
1276
+ ctx[property] = this._applyPatternGradientTransformText(filler);
1277
+ return { offsetX, offsetY };
1278
+ } else {
1279
+ // is a simple gradient or pattern
1280
+ ctx[property] = filler.toLive(ctx)!;
1281
+ return this._applyPatternGradientTransform(ctx, filler);
1282
+ }
1283
+ } else {
1284
+ // is a color
1285
+ ctx[property] = filler;
1286
+ }
1287
+ return { offsetX: 0, offsetY: 0 };
1288
+ }
1289
+
1290
+ /**
1291
+ * This function prepare the canvas for a stroke style, and stroke and strokeWidth
1292
+ * need to be sent in as defined
1293
+ * @param {CanvasRenderingContext2D} ctx
1294
+ * @param {CompleteTextStyleDeclaration} style with stroke and strokeWidth defined
1295
+ * @returns
1296
+ */
1297
+ _setStrokeStyles(
1298
+ ctx: CanvasRenderingContext2D,
1299
+ {
1300
+ stroke,
1301
+ strokeWidth,
1302
+ }: Pick<CompleteTextStyleDeclaration, 'stroke' | 'strokeWidth'>
1303
+ ) {
1304
+ ctx.lineWidth = strokeWidth;
1305
+ ctx.lineCap = this.strokeLineCap;
1306
+ ctx.lineDashOffset = this.strokeDashOffset;
1307
+ ctx.lineJoin = this.strokeLineJoin;
1308
+ ctx.miterLimit = this.strokeMiterLimit;
1309
+ return this.handleFiller(ctx, 'strokeStyle', stroke!);
1310
+ }
1311
+
1312
+ /**
1313
+ * This function prepare the canvas for a ill style, and fill
1314
+ * need to be sent in as defined
1315
+ * @param {CanvasRenderingContext2D} ctx
1316
+ * @param {CompleteTextStyleDeclaration} style with ill defined
1317
+ * @returns
1318
+ */
1319
+ _setFillStyles(ctx: CanvasRenderingContext2D, { fill }: Pick<this, 'fill'>) {
1320
+ return this.handleFiller(ctx, 'fillStyle', fill!);
1321
+ }
1322
+
1323
+ /**
1324
+ * @private
1325
+ * @param {String} method
1326
+ * @param {CanvasRenderingContext2D} ctx Context to render on
1327
+ * @param {Number} lineIndex
1328
+ * @param {Number} charIndex
1329
+ * @param {String} _char
1330
+ * @param {Number} left Left coordinate
1331
+ * @param {Number} top Top coordinate
1332
+ * @param {Number} lineHeight Height of the line
1333
+ */
1334
+ _renderChar(
1335
+ method: 'fillText' | 'strokeText',
1336
+ ctx: CanvasRenderingContext2D,
1337
+ lineIndex: number,
1338
+ charIndex: number,
1339
+ _char: string,
1340
+ left: number,
1341
+ top: number
1342
+ ) {
1343
+ const decl = this._getStyleDeclaration(lineIndex, charIndex),
1344
+ fullDecl = this.getCompleteStyleDeclaration(lineIndex, charIndex),
1345
+ shouldFill = method === 'fillText' && fullDecl.fill,
1346
+ shouldStroke =
1347
+ method === 'strokeText' && fullDecl.stroke && fullDecl.strokeWidth;
1348
+
1349
+ if (!shouldStroke && !shouldFill) {
1350
+ return;
1351
+ }
1352
+ ctx.save();
1353
+
1354
+ ctx.font = this._getFontDeclaration(fullDecl);
1355
+
1356
+ if (decl.textBackgroundColor) {
1357
+ this._removeShadow(ctx);
1358
+ }
1359
+ if (decl.deltaY) {
1360
+ top += decl.deltaY;
1361
+ }
1362
+
1363
+ if (shouldFill) {
1364
+ const fillOffsets = this._setFillStyles(ctx, fullDecl);
1365
+ ctx.fillText(
1366
+ _char,
1367
+ left - fillOffsets.offsetX,
1368
+ top - fillOffsets.offsetY
1369
+ );
1370
+ }
1371
+
1372
+ if (shouldStroke) {
1373
+ const strokeOffsets = this._setStrokeStyles(ctx, fullDecl);
1374
+ ctx.strokeText(
1375
+ _char,
1376
+ left - strokeOffsets.offsetX,
1377
+ top - strokeOffsets.offsetY
1378
+ );
1379
+ }
1380
+
1381
+ ctx.restore();
1382
+ }
1383
+
1384
+ /**
1385
+ * Turns the character into a 'superior figure' (i.e. 'superscript')
1386
+ * @param {Number} start selection start
1387
+ * @param {Number} end selection end
1388
+ */
1389
+ setSuperscript(start: number, end: number) {
1390
+ this._setScript(start, end, this.superscript);
1391
+ }
1392
+
1393
+ /**
1394
+ * Turns the character into an 'inferior figure' (i.e. 'subscript')
1395
+ * @param {Number} start selection start
1396
+ * @param {Number} end selection end
1397
+ */
1398
+ setSubscript(start: number, end: number) {
1399
+ this._setScript(start, end, this.subscript);
1400
+ }
1401
+
1402
+ /**
1403
+ * Applies 'schema' at given position
1404
+ * @private
1405
+ * @param {Number} start selection start
1406
+ * @param {Number} end selection end
1407
+ * @param {Number} schema
1408
+ */
1409
+ protected _setScript(
1410
+ start: number,
1411
+ end: number,
1412
+ schema: {
1413
+ size: number;
1414
+ baseline: number;
1415
+ }
1416
+ ) {
1417
+ const loc = this.get2DCursorLocation(start, true),
1418
+ fontSize = this.getValueOfPropertyAt(
1419
+ loc.lineIndex,
1420
+ loc.charIndex,
1421
+ 'fontSize'
1422
+ ),
1423
+ dy = this.getValueOfPropertyAt(loc.lineIndex, loc.charIndex, 'deltaY'),
1424
+ style = {
1425
+ fontSize: fontSize * schema.size,
1426
+ deltaY: dy + fontSize * schema.baseline,
1427
+ };
1428
+ this.setSelectionStyles(style, start, end);
1429
+ }
1430
+
1431
+ /**
1432
+ * @private
1433
+ * @param {Number} lineIndex index text line
1434
+ * @return {Number} Line left offset
1435
+ */
1436
+ _getLineLeftOffset(lineIndex: number): number {
1437
+ const lineWidth = this.getLineWidth(lineIndex),
1438
+ lineDiff = this.width - lineWidth,
1439
+ textAlign = this.textAlign,
1440
+ direction = this.direction,
1441
+ isEndOfWrapping = this.isEndOfWrapping(lineIndex);
1442
+ let leftOffset = 0;
1443
+ if (
1444
+ textAlign === JUSTIFY ||
1445
+ (textAlign === JUSTIFY_CENTER && !isEndOfWrapping) ||
1446
+ (textAlign === JUSTIFY_RIGHT && !isEndOfWrapping) ||
1447
+ (textAlign === JUSTIFY_LEFT && !isEndOfWrapping)
1448
+ ) {
1449
+ return 0;
1450
+ }
1451
+ if (textAlign === CENTER) {
1452
+ leftOffset = lineDiff / 2;
1453
+ }
1454
+ if (textAlign === RIGHT) {
1455
+ leftOffset = lineDiff;
1456
+ }
1457
+ if (textAlign === JUSTIFY_CENTER) {
1458
+ leftOffset = lineDiff / 2;
1459
+ }
1460
+ if (textAlign === JUSTIFY_RIGHT) {
1461
+ leftOffset = lineDiff;
1462
+ }
1463
+ if (direction === 'rtl') {
1464
+ if (
1465
+ textAlign === RIGHT ||
1466
+ textAlign === JUSTIFY ||
1467
+ textAlign === JUSTIFY_RIGHT
1468
+ ) {
1469
+ leftOffset = 0;
1470
+ } else if (textAlign === LEFT || textAlign === JUSTIFY_LEFT) {
1471
+ leftOffset = -lineDiff;
1472
+ } else if (textAlign === CENTER || textAlign === JUSTIFY_CENTER) {
1473
+ leftOffset = -lineDiff / 2;
1474
+ }
1475
+ }
1476
+ return leftOffset;
1477
+ }
1478
+
1479
+ /**
1480
+ * @private
1481
+ */
1482
+ _clearCache() {
1483
+ this._forceClearCache = false;
1484
+ this.__lineWidths = [];
1485
+ this.__lineHeights = [];
1486
+ this.__charBounds = [];
1487
+ }
1488
+
1489
+ /**
1490
+ * Measure a single line given its index. Used to calculate the initial
1491
+ * text bounding box. The values are calculated and stored in __lineWidths cache.
1492
+ * @private
1493
+ * @param {Number} lineIndex line number
1494
+ * @return {Number} Line width
1495
+ */
1496
+ getLineWidth(lineIndex: number): number {
1497
+ if (this.__lineWidths[lineIndex] !== undefined) {
1498
+ return this.__lineWidths[lineIndex];
1499
+ }
1500
+
1501
+ const { width } = this.measureLine(lineIndex);
1502
+ this.__lineWidths[lineIndex] = width;
1503
+ return width;
1504
+ }
1505
+
1506
+ _getWidthOfCharSpacing() {
1507
+ if (this.charSpacing !== 0) {
1508
+ return (this.fontSize * this.charSpacing) / 1000;
1509
+ }
1510
+ return 0;
1511
+ }
1512
+
1513
+ /**
1514
+ * Retrieves the value of property at given character position
1515
+ * @param {Number} lineIndex the line number
1516
+ * @param {Number} charIndex the character number
1517
+ * @param {String} property the property name
1518
+ * @returns the value of 'property'
1519
+ */
1520
+ getValueOfPropertyAt<T extends StylePropertiesType>(
1521
+ lineIndex: number,
1522
+ charIndex: number,
1523
+ property: T
1524
+ ): this[T] {
1525
+ const charStyle = this._getStyleDeclaration(lineIndex, charIndex);
1526
+ return (charStyle[property] ?? this[property]) as this[T];
1527
+ }
1528
+
1529
+ /**
1530
+ * @private
1531
+ * @param {CanvasRenderingContext2D} ctx Context to render on
1532
+ */
1533
+ _renderTextDecoration(
1534
+ ctx: CanvasRenderingContext2D,
1535
+ type: 'underline' | 'linethrough' | 'overline'
1536
+ ) {
1537
+ if (!this[type] && !this.styleHas(type)) {
1538
+ return;
1539
+ }
1540
+ let topOffset = this._getTopOffset();
1541
+ const leftOffset = this._getLeftOffset(),
1542
+ path = this.path,
1543
+ charSpacing = this._getWidthOfCharSpacing(),
1544
+ offsetY = this.offsets[type];
1545
+
1546
+ for (let i = 0, len = this._textLines.length; i < len; i++) {
1547
+ const heightOfLine = this.getHeightOfLine(i);
1548
+ if (!this[type] && !this.styleHas(type, i)) {
1549
+ topOffset += heightOfLine;
1550
+ continue;
1551
+ }
1552
+ const line = this._textLines[i];
1553
+ const maxHeight = heightOfLine / this.lineHeight;
1554
+ const lineLeftOffset = this._getLineLeftOffset(i);
1555
+ let boxStart = 0;
1556
+ let boxWidth = 0;
1557
+ let lastDecoration = this.getValueOfPropertyAt(i, 0, type);
1558
+ let lastFill = this.getValueOfPropertyAt(i, 0, 'fill');
1559
+ let currentDecoration;
1560
+ let currentFill;
1561
+ const top = topOffset + maxHeight * (1 - this._fontSizeFraction);
1562
+ let size = this.getHeightOfChar(i, 0);
1563
+ let dy = this.getValueOfPropertyAt(i, 0, 'deltaY');
1564
+ for (let j = 0, jlen = line.length; j < jlen; j++) {
1565
+ const charBox = this.__charBounds[i][j] as Required<GraphemeBBox>;
1566
+ currentDecoration = this.getValueOfPropertyAt(i, j, type);
1567
+ currentFill = this.getValueOfPropertyAt(i, j, 'fill');
1568
+ const currentSize = this.getHeightOfChar(i, j);
1569
+ const currentDy = this.getValueOfPropertyAt(i, j, 'deltaY');
1570
+ if (path && currentDecoration && currentFill) {
1571
+ ctx.save();
1572
+ // bug? verify lastFill is a valid fill here.
1573
+ ctx.fillStyle = lastFill as string;
1574
+ ctx.translate(charBox.renderLeft, charBox.renderTop);
1575
+ ctx.rotate(charBox.angle);
1576
+ ctx.fillRect(
1577
+ -charBox.kernedWidth / 2,
1578
+ offsetY * currentSize + currentDy,
1579
+ charBox.kernedWidth,
1580
+ this.fontSize / 15
1581
+ );
1582
+ ctx.restore();
1583
+ } else if (
1584
+ (currentDecoration !== lastDecoration ||
1585
+ currentFill !== lastFill ||
1586
+ currentSize !== size ||
1587
+ currentDy !== dy) &&
1588
+ boxWidth > 0
1589
+ ) {
1590
+ let drawStart = leftOffset + lineLeftOffset + boxStart;
1591
+ if (this.direction === 'rtl') {
1592
+ drawStart = this.width - drawStart - boxWidth;
1593
+ }
1594
+ if (lastDecoration && lastFill) {
1595
+ // bug? verify lastFill is a valid fill here.
1596
+ ctx.fillStyle = lastFill as string;
1597
+ ctx.fillRect(
1598
+ drawStart,
1599
+ top + offsetY * size + dy,
1600
+ boxWidth,
1601
+ this.fontSize / 15
1602
+ );
1603
+ }
1604
+ boxStart = charBox.left;
1605
+ boxWidth = charBox.width;
1606
+ lastDecoration = currentDecoration;
1607
+ lastFill = currentFill;
1608
+ size = currentSize;
1609
+ dy = currentDy;
1610
+ } else {
1611
+ boxWidth += charBox.kernedWidth;
1612
+ }
1613
+ }
1614
+ let drawStart = leftOffset + lineLeftOffset + boxStart;
1615
+ if (this.direction === 'rtl') {
1616
+ drawStart = this.width - drawStart - boxWidth;
1617
+ }
1618
+ ctx.fillStyle = currentFill as string;
1619
+ currentDecoration &&
1620
+ currentFill &&
1621
+ ctx.fillRect(
1622
+ drawStart,
1623
+ top + offsetY * size + dy,
1624
+ boxWidth - charSpacing,
1625
+ this.fontSize / 15
1626
+ );
1627
+ topOffset += heightOfLine;
1628
+ }
1629
+ // if there is text background color no
1630
+ // other shadows should be casted
1631
+ this._removeShadow(ctx);
1632
+ }
1633
+
1634
+ /**
1635
+ * return font declaration string for canvas context
1636
+ * @param {Object} [styleObject] object
1637
+ * @returns {String} font declaration formatted for canvas context.
1638
+ */
1639
+ _getFontDeclaration(
1640
+ styleObject?: TextStyleDeclaration,
1641
+ forMeasuring?: boolean
1642
+ ): string {
1643
+ const style = styleObject || this,
1644
+ family = this.fontFamily,
1645
+ fontIsGeneric = Text.genericFonts.indexOf(family.toLowerCase()) > -1;
1646
+ const fontFamily =
1647
+ family === undefined ||
1648
+ family.indexOf("'") > -1 ||
1649
+ family.indexOf(',') > -1 ||
1650
+ family.indexOf('"') > -1 ||
1651
+ fontIsGeneric
1652
+ ? style.fontFamily
1653
+ : `"${style.fontFamily}"`;
1654
+ return [
1655
+ style.fontStyle,
1656
+ style.fontWeight,
1657
+ forMeasuring ? this.CACHE_FONT_SIZE + 'px' : style.fontSize + 'px',
1658
+ fontFamily,
1659
+ ].join(' ');
1660
+ }
1661
+
1662
+ /**
1663
+ * Renders text instance on a specified context
1664
+ * @param {CanvasRenderingContext2D} ctx Context to render on
1665
+ */
1666
+ render(ctx: CanvasRenderingContext2D) {
1667
+ if (!this.visible) {
1668
+ return;
1669
+ }
1670
+ if (
1671
+ this.canvas &&
1672
+ this.canvas.skipOffscreen &&
1673
+ !this.group &&
1674
+ !this.isOnScreen()
1675
+ ) {
1676
+ return;
1677
+ }
1678
+ if (this._forceClearCache) {
1679
+ this.initDimensions();
1680
+ }
1681
+ super.render(ctx);
1682
+ }
1683
+
1684
+ /**
1685
+ * Override this method to customize grapheme splitting
1686
+ * @todo the util `graphemeSplit` needs to be injectable in some way.
1687
+ * is more comfortable to inject the correct util rather than having to override text
1688
+ * in the middle of the prototype chain
1689
+ * @param {string} value
1690
+ * @returns {string[]} array of graphemes
1691
+ */
1692
+ graphemeSplit(value: string): string[] {
1693
+ return graphemeSplit(value);
1694
+ }
1695
+
1696
+ /**
1697
+ * Returns the text as an array of lines.
1698
+ * @param {String} text text to split
1699
+ * @returns Lines in the text
1700
+ */
1701
+ _splitTextIntoLines(text: string) {
1702
+ const lines = text.split(this._reNewline),
1703
+ newLines = new Array<string[]>(lines.length),
1704
+ newLine = ['\n'];
1705
+ let newText: string[] = [];
1706
+ for (let i = 0; i < lines.length; i++) {
1707
+ newLines[i] = this.graphemeSplit(lines[i]);
1708
+ newText = newText.concat(newLines[i], newLine);
1709
+ }
1710
+ newText.pop();
1711
+ return {
1712
+ _unwrappedLines: newLines,
1713
+ lines: lines,
1714
+ graphemeText: newText,
1715
+ graphemeLines: newLines,
1716
+ };
1717
+ }
1718
+
1719
+ /**
1720
+ * Returns object representation of an instance
1721
+ * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
1722
+ * @return {Object} Object representation of an instance
1723
+ */
1724
+ toObject<
1725
+ T extends Omit<Props & TClassProperties<this>, keyof SProps>,
1726
+ K extends keyof T = never
1727
+ >(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
1728
+ return {
1729
+ ...super.toObject([...additionalProps, ...propertiesToInclude]),
1730
+ styles: stylesToArray(this.styles, this.text),
1731
+ ...(this.path ? { path: this.path.toObject() } : {}),
1732
+ };
1733
+ }
1734
+
1735
+ set(key: string | any, value?: any) {
1736
+ const { textLayoutProperties } = this.constructor as typeof Text;
1737
+ super.set(key, value);
1738
+ let needsDims = false;
1739
+ let isAddingPath = false;
1740
+ if (typeof key === 'object') {
1741
+ for (const _key in key) {
1742
+ if (_key === 'path') {
1743
+ this.setPathInfo();
1744
+ }
1745
+ needsDims = needsDims || textLayoutProperties.includes(_key);
1746
+ isAddingPath = isAddingPath || _key === 'path';
1747
+ }
1748
+ } else {
1749
+ needsDims = textLayoutProperties.includes(key);
1750
+ isAddingPath = key === 'path';
1751
+ }
1752
+ if (isAddingPath) {
1753
+ this.setPathInfo();
1754
+ }
1755
+ if (needsDims && this.initialized) {
1756
+ this.initDimensions();
1757
+ this.setCoords();
1758
+ }
1759
+ return this;
1760
+ }
1761
+
1762
+ /**
1763
+ * Returns complexity of an instance
1764
+ * @return {Number} complexity
1765
+ */
1766
+ complexity(): number {
1767
+ return 1;
1768
+ }
1769
+
1770
+ static genericFonts = [
1771
+ 'sans-serif',
1772
+ 'serif',
1773
+ 'cursive',
1774
+ 'fantasy',
1775
+ 'monospace',
1776
+ ];
1777
+
1778
+ /* _FROM_SVG_START_ */
1779
+
1780
+ /**
1781
+ * List of attribute names to account for when parsing SVG element (used by {@link Text.fromElement})
1782
+ * @static
1783
+ * @memberOf Text
1784
+ * @see: http://www.w3.org/TR/SVG/text.html#TextElement
1785
+ */
1786
+ static ATTRIBUTE_NAMES = SHARED_ATTRIBUTES.concat(
1787
+ 'x',
1788
+ 'y',
1789
+ 'dx',
1790
+ 'dy',
1791
+ 'font-family',
1792
+ 'font-style',
1793
+ 'font-weight',
1794
+ 'font-size',
1795
+ 'letter-spacing',
1796
+ 'text-decoration',
1797
+ 'text-anchor'
1798
+ );
1799
+
1800
+ /**
1801
+ * Returns Text instance from an SVG element (<b>not yet implemented</b>)
1802
+ * @static
1803
+ * @memberOf Text
1804
+ * @param {SVGElement} element Element to parse
1805
+ * @param {Object} [options] Options object
1806
+ */
1807
+ static async fromElement(element: SVGElement, options: object) {
1808
+ const parsedAttributes = parseAttributes(element, Text.ATTRIBUTE_NAMES);
1809
+
1810
+ const {
1811
+ textAnchor = LEFT as typeof LEFT | typeof CENTER | typeof RIGHT,
1812
+ textDecoration = '',
1813
+ dx = 0,
1814
+ dy = 0,
1815
+ top = 0,
1816
+ left = 0,
1817
+ fontSize = DEFAULT_SVG_FONT_SIZE,
1818
+ strokeWidth = 1,
1819
+ ...restOfOptions
1820
+ } = { ...options, ...parsedAttributes };
1821
+
1822
+ const textContent = (element.textContent || '')
1823
+ .replace(/^\s+|\s+$|\n+/g, '')
1824
+ .replace(/\s+/g, ' ');
1825
+
1826
+ // this code here is probably the usual issue for SVG center find
1827
+ // this can later looked at again and probably removed.
1828
+
1829
+ const text = new this(textContent, {
1830
+ left: left + dx,
1831
+ top: top + dy,
1832
+ underline: textDecoration.includes('underline'),
1833
+ overline: textDecoration.includes('overline'),
1834
+ linethrough: textDecoration.includes('line-through'),
1835
+ // we initialize this as 0
1836
+ strokeWidth: 0,
1837
+ fontSize,
1838
+ ...restOfOptions,
1839
+ }),
1840
+ textHeightScaleFactor = text.getScaledHeight() / text.height,
1841
+ lineHeightDiff =
1842
+ (text.height + text.strokeWidth) * text.lineHeight - text.height,
1843
+ scaledDiff = lineHeightDiff * textHeightScaleFactor,
1844
+ textHeight = text.getScaledHeight() + scaledDiff;
1845
+
1846
+ let offX = 0;
1847
+ /*
1848
+ Adjust positioning:
1849
+ x/y attributes in SVG correspond to the bottom-left corner of text bounding box
1850
+ fabric output by default at top, left.
1851
+ */
1852
+ if (textAnchor === CENTER) {
1853
+ offX = text.getScaledWidth() / 2;
1854
+ }
1855
+ if (textAnchor === RIGHT) {
1856
+ offX = text.getScaledWidth();
1857
+ }
1858
+ text.set({
1859
+ left: text.left - offX,
1860
+ top:
1861
+ text.top -
1862
+ (textHeight - text.fontSize * (0.07 + text._fontSizeFraction)) /
1863
+ text.lineHeight,
1864
+ strokeWidth,
1865
+ });
1866
+ return text;
1867
+ }
1868
+
1869
+ /* _FROM_SVG_END_ */
1870
+
1871
+ /**
1872
+ * Returns Text instance from an object representation
1873
+ * @param {Object} object plain js Object to create an instance from
1874
+ * @returns {Promise<Text>}
1875
+ */
1876
+ static fromObject<T extends TProps<SerializedTextProps>>(object: T) {
1877
+ return this._fromObject<Text>(
1878
+ {
1879
+ ...object,
1880
+ styles: stylesFromArray(object.styles || {}, object.text),
1881
+ },
1882
+ {
1883
+ extraParam: 'text',
1884
+ }
1885
+ );
1886
+ }
1887
+ }
1888
+
1889
+ applyMixins(Text, [TextSVGExportMixin]);
1890
+ classRegistry.setClass(Text);
1891
+ classRegistry.setSVGClass(Text);