fabric 5.3.0 → 6.0.0-beta3

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