@nasser-sw/fabric 7.0.0-beta1 → 7.0.1-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 (183) hide show
  1. package/0 +0 -0
  2. package/debug/{konva → konva-master}/CHANGELOG.md +2 -1
  3. package/debug/{konva → konva-master}/README.md +7 -3
  4. package/debug/{konva → konva-master}/package.json +1 -1
  5. package/debug/{konva → konva-master}/release.sh +1 -4
  6. package/debug/{konva → konva-master}/src/Canvas.ts +37 -0
  7. package/debug/{konva → konva-master}/src/shapes/Text.ts +2 -2
  8. package/dist/index.js +2198 -272
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.min.js +1 -1
  11. package/dist/index.min.js.map +1 -1
  12. package/dist/index.min.mjs +1 -1
  13. package/dist/index.min.mjs.map +1 -1
  14. package/dist/index.mjs +2198 -272
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/index.node.cjs +2198 -272
  17. package/dist/index.node.cjs.map +1 -1
  18. package/dist/index.node.mjs +2198 -272
  19. package/dist/index.node.mjs.map +1 -1
  20. package/dist/package.json.min.mjs +1 -1
  21. package/dist/package.json.mjs +1 -1
  22. package/dist/src/shapes/Line.d.ts +33 -86
  23. package/dist/src/shapes/Line.d.ts.map +1 -1
  24. package/dist/src/shapes/Line.min.mjs +1 -1
  25. package/dist/src/shapes/Line.min.mjs.map +1 -1
  26. package/dist/src/shapes/Line.mjs +405 -159
  27. package/dist/src/shapes/Line.mjs.map +1 -1
  28. package/dist/src/shapes/Polyline.d.ts +7 -0
  29. package/dist/src/shapes/Polyline.d.ts.map +1 -1
  30. package/dist/src/shapes/Polyline.min.mjs +1 -1
  31. package/dist/src/shapes/Polyline.min.mjs.map +1 -1
  32. package/dist/src/shapes/Polyline.mjs +48 -16
  33. package/dist/src/shapes/Polyline.mjs.map +1 -1
  34. package/dist/src/shapes/Text/Text.d.ts +19 -0
  35. package/dist/src/shapes/Text/Text.d.ts.map +1 -1
  36. package/dist/src/shapes/Text/Text.min.mjs +1 -1
  37. package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
  38. package/dist/src/shapes/Text/Text.mjs +302 -16
  39. package/dist/src/shapes/Text/Text.mjs.map +1 -1
  40. package/dist/src/shapes/Textbox.d.ts +56 -1
  41. package/dist/src/shapes/Textbox.d.ts.map +1 -1
  42. package/dist/src/shapes/Textbox.min.mjs +1 -1
  43. package/dist/src/shapes/Textbox.min.mjs.map +1 -1
  44. package/dist/src/shapes/Textbox.mjs +633 -11
  45. package/dist/src/shapes/Textbox.mjs.map +1 -1
  46. package/dist/src/shapes/Triangle.d.ts +27 -2
  47. package/dist/src/shapes/Triangle.d.ts.map +1 -1
  48. package/dist/src/shapes/Triangle.min.mjs +1 -1
  49. package/dist/src/shapes/Triangle.min.mjs.map +1 -1
  50. package/dist/src/shapes/Triangle.mjs +72 -12
  51. package/dist/src/shapes/Triangle.mjs.map +1 -1
  52. package/dist/src/text/examples/arabicTextExample.d.ts +60 -0
  53. package/dist/src/text/examples/arabicTextExample.d.ts.map +1 -0
  54. package/dist/src/text/measure.d.ts +9 -0
  55. package/dist/src/text/measure.d.ts.map +1 -1
  56. package/dist/src/text/measure.min.mjs +1 -1
  57. package/dist/src/text/measure.min.mjs.map +1 -1
  58. package/dist/src/text/measure.mjs +175 -4
  59. package/dist/src/text/measure.mjs.map +1 -1
  60. package/dist/src/text/overlayEditor.d.ts +8 -0
  61. package/dist/src/text/overlayEditor.d.ts.map +1 -1
  62. package/dist/src/text/overlayEditor.min.mjs +1 -1
  63. package/dist/src/text/overlayEditor.min.mjs.map +1 -1
  64. package/dist/src/text/overlayEditor.mjs +395 -56
  65. package/dist/src/text/overlayEditor.mjs.map +1 -1
  66. package/dist/src/text/scriptUtils.d.ts +142 -0
  67. package/dist/src/text/scriptUtils.d.ts.map +1 -0
  68. package/dist/src/text/scriptUtils.min.mjs +2 -0
  69. package/dist/src/text/scriptUtils.min.mjs.map +1 -0
  70. package/dist/src/text/scriptUtils.mjs +212 -0
  71. package/dist/src/text/scriptUtils.mjs.map +1 -0
  72. package/dist/src/util/misc/cornerRadius.d.ts +70 -0
  73. package/dist/src/util/misc/cornerRadius.d.ts.map +1 -0
  74. package/dist/src/util/misc/cornerRadius.min.mjs +2 -0
  75. package/dist/src/util/misc/cornerRadius.min.mjs.map +1 -0
  76. package/dist/src/util/misc/cornerRadius.mjs +181 -0
  77. package/dist/src/util/misc/cornerRadius.mjs.map +1 -0
  78. package/dist-extensions/src/shapes/CustomLine.d.ts +10 -0
  79. package/dist-extensions/src/shapes/CustomLine.d.ts.map +1 -0
  80. package/dist-extensions/src/shapes/Line.d.ts +33 -86
  81. package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
  82. package/dist-extensions/src/shapes/Polyline.d.ts +7 -0
  83. package/dist-extensions/src/shapes/Polyline.d.ts.map +1 -1
  84. package/dist-extensions/src/shapes/Text/Text.d.ts +19 -0
  85. package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
  86. package/dist-extensions/src/shapes/Textbox.d.ts +56 -1
  87. package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
  88. package/dist-extensions/src/shapes/Triangle.d.ts +27 -2
  89. package/dist-extensions/src/shapes/Triangle.d.ts.map +1 -1
  90. package/dist-extensions/src/text/measure.d.ts +9 -0
  91. package/dist-extensions/src/text/measure.d.ts.map +1 -1
  92. package/dist-extensions/src/text/overlayEditor.d.ts +8 -0
  93. package/dist-extensions/src/text/overlayEditor.d.ts.map +1 -1
  94. package/dist-extensions/src/text/scriptUtils.d.ts +142 -0
  95. package/dist-extensions/src/text/scriptUtils.d.ts.map +1 -0
  96. package/dist-extensions/src/util/misc/cornerRadius.d.ts +70 -0
  97. package/dist-extensions/src/util/misc/cornerRadius.d.ts.map +1 -0
  98. package/fabric-test-editor.html +3552 -0
  99. package/fabric-test2.html +647 -0
  100. package/fabric.ts +182 -182
  101. package/fonts/STV Bold.ttf +0 -0
  102. package/fonts/STV Light.ttf +0 -0
  103. package/fonts/STV Regular.ttf +0 -0
  104. package/package.json +164 -164
  105. package/src/shapes/Line.ts +484 -157
  106. package/src/shapes/Polyline.ts +70 -29
  107. package/src/shapes/Text/Text.ts +317 -19
  108. package/src/shapes/Textbox.ts +663 -12
  109. package/src/shapes/Triangle.spec.ts +76 -0
  110. package/src/shapes/Triangle.ts +85 -15
  111. package/src/text/measure.ts +200 -50
  112. package/src/text/overlayEditor.ts +504 -94
  113. package/src/util/misc/cornerRadius.spec.ts +141 -0
  114. package/src/util/misc/cornerRadius.ts +269 -0
  115. /package/debug/{konva → konva-master}/LICENSE +0 -0
  116. /package/debug/{konva → konva-master}/gulpfile.mjs +0 -0
  117. /package/debug/{konva → konva-master}/resources/doc-includes/ContainerParams.txt +0 -0
  118. /package/debug/{konva → konva-master}/resources/doc-includes/NodeParams.txt +0 -0
  119. /package/debug/{konva → konva-master}/resources/doc-includes/ShapeParams.txt +0 -0
  120. /package/debug/{konva → konva-master}/resources/jsdoc.conf.json +0 -0
  121. /package/debug/{konva → konva-master}/rollup.config.mjs +0 -0
  122. /package/debug/{konva → konva-master}/src/Animation.ts +0 -0
  123. /package/debug/{konva → konva-master}/src/BezierFunctions.ts +0 -0
  124. /package/debug/{konva → konva-master}/src/Container.ts +0 -0
  125. /package/debug/{konva → konva-master}/src/Context.ts +0 -0
  126. /package/debug/{konva → konva-master}/src/Core.ts +0 -0
  127. /package/debug/{konva → konva-master}/src/DragAndDrop.ts +0 -0
  128. /package/debug/{konva → konva-master}/src/Factory.ts +0 -0
  129. /package/debug/{konva → konva-master}/src/FastLayer.ts +0 -0
  130. /package/debug/{konva → konva-master}/src/Global.ts +0 -0
  131. /package/debug/{konva → konva-master}/src/Group.ts +0 -0
  132. /package/debug/{konva → konva-master}/src/Layer.ts +0 -0
  133. /package/debug/{konva → konva-master}/src/Node.ts +0 -0
  134. /package/debug/{konva → konva-master}/src/PointerEvents.ts +0 -0
  135. /package/debug/{konva → konva-master}/src/Shape.ts +0 -0
  136. /package/debug/{konva → konva-master}/src/Stage.ts +0 -0
  137. /package/debug/{konva → konva-master}/src/Tween.ts +0 -0
  138. /package/debug/{konva → konva-master}/src/Util.ts +0 -0
  139. /package/debug/{konva → konva-master}/src/Validators.ts +0 -0
  140. /package/debug/{konva → konva-master}/src/_CoreInternals.ts +0 -0
  141. /package/debug/{konva → konva-master}/src/_FullInternals.ts +0 -0
  142. /package/debug/{konva → konva-master}/src/canvas-backend.ts +0 -0
  143. /package/debug/{konva → konva-master}/src/filters/Blur.ts +0 -0
  144. /package/debug/{konva → konva-master}/src/filters/Brighten.ts +0 -0
  145. /package/debug/{konva → konva-master}/src/filters/Brightness.ts +0 -0
  146. /package/debug/{konva → konva-master}/src/filters/Contrast.ts +0 -0
  147. /package/debug/{konva → konva-master}/src/filters/Emboss.ts +0 -0
  148. /package/debug/{konva → konva-master}/src/filters/Enhance.ts +0 -0
  149. /package/debug/{konva → konva-master}/src/filters/Grayscale.ts +0 -0
  150. /package/debug/{konva → konva-master}/src/filters/HSL.ts +0 -0
  151. /package/debug/{konva → konva-master}/src/filters/HSV.ts +0 -0
  152. /package/debug/{konva → konva-master}/src/filters/Invert.ts +0 -0
  153. /package/debug/{konva → konva-master}/src/filters/Kaleidoscope.ts +0 -0
  154. /package/debug/{konva → konva-master}/src/filters/Mask.ts +0 -0
  155. /package/debug/{konva → konva-master}/src/filters/Noise.ts +0 -0
  156. /package/debug/{konva → konva-master}/src/filters/Pixelate.ts +0 -0
  157. /package/debug/{konva → konva-master}/src/filters/Posterize.ts +0 -0
  158. /package/debug/{konva → konva-master}/src/filters/RGB.ts +0 -0
  159. /package/debug/{konva → konva-master}/src/filters/RGBA.ts +0 -0
  160. /package/debug/{konva → konva-master}/src/filters/Sepia.ts +0 -0
  161. /package/debug/{konva → konva-master}/src/filters/Solarize.ts +0 -0
  162. /package/debug/{konva → konva-master}/src/filters/Threshold.ts +0 -0
  163. /package/debug/{konva → konva-master}/src/index.ts +0 -0
  164. /package/debug/{konva → konva-master}/src/shapes/Arc.ts +0 -0
  165. /package/debug/{konva → konva-master}/src/shapes/Arrow.ts +0 -0
  166. /package/debug/{konva → konva-master}/src/shapes/Circle.ts +0 -0
  167. /package/debug/{konva → konva-master}/src/shapes/Ellipse.ts +0 -0
  168. /package/debug/{konva → konva-master}/src/shapes/Image.ts +0 -0
  169. /package/debug/{konva → konva-master}/src/shapes/Label.ts +0 -0
  170. /package/debug/{konva → konva-master}/src/shapes/Line.ts +0 -0
  171. /package/debug/{konva → konva-master}/src/shapes/Path.ts +0 -0
  172. /package/debug/{konva → konva-master}/src/shapes/Rect.ts +0 -0
  173. /package/debug/{konva → konva-master}/src/shapes/RegularPolygon.ts +0 -0
  174. /package/debug/{konva → konva-master}/src/shapes/Ring.ts +0 -0
  175. /package/debug/{konva → konva-master}/src/shapes/Sprite.ts +0 -0
  176. /package/debug/{konva → konva-master}/src/shapes/Star.ts +0 -0
  177. /package/debug/{konva → konva-master}/src/shapes/TextPath.ts +0 -0
  178. /package/debug/{konva → konva-master}/src/shapes/Transformer.ts +0 -0
  179. /package/debug/{konva → konva-master}/src/shapes/Wedge.ts +0 -0
  180. /package/debug/{konva → konva-master}/src/skia-backend.ts +0 -0
  181. /package/debug/{konva → konva-master}/src/types.ts +0 -0
  182. /package/debug/{konva → konva-master}/tsconfig.json +0 -0
  183. /package/debug/{konva → konva-master}/tsconfig.test.json +0 -0
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Script Detection and Font Metrics Utilities
3
+ *
4
+ * Provides script-aware text measurement for improved bounding box calculations
5
+ * across different writing systems like Arabic, Latin, CJK, etc.
6
+ */
7
+
8
+ /**
9
+ * Unicode ranges for different scripts
10
+ */
11
+ const SCRIPT_RANGES = {
12
+ latin: [[0x0000, 0x007F],
13
+ // Basic Latin
14
+ [0x0080, 0x00FF],
15
+ // Latin-1 Supplement
16
+ [0x0100, 0x017F],
17
+ // Latin Extended-A
18
+ [0x0180, 0x024F],
19
+ // Latin Extended-B
20
+ [0x1E00, 0x1EFF] // Latin Extended Additional
21
+ ],
22
+ arabic: [[0x0600, 0x06FF],
23
+ // Arabic
24
+ [0x0750, 0x077F],
25
+ // Arabic Supplement
26
+ [0x08A0, 0x08FF],
27
+ // Arabic Extended-A
28
+ [0xFB50, 0xFDFF],
29
+ // Arabic Presentation Forms-A
30
+ [0xFE70, 0xFEFF] // Arabic Presentation Forms-B
31
+ ],
32
+ hebrew: [[0x0590, 0x05FF],
33
+ // Hebrew
34
+ [0xFB1D, 0xFB4F] // Hebrew Presentation Forms
35
+ ],
36
+ cjk: [[0x2E80, 0x2EFF],
37
+ // CJK Radicals Supplement
38
+ [0x3000, 0x303F],
39
+ // CJK Symbols and Punctuation
40
+ [0x3400, 0x4DBF],
41
+ // CJK Extension A
42
+ [0x4E00, 0x9FFF],
43
+ // CJK Unified Ideographs
44
+ [0xF900, 0xFAFF],
45
+ // CJK Compatibility Ideographs
46
+ [0x20000, 0x2A6DF] // CJK Extension B
47
+ ],
48
+ devanagari: [[0x0900, 0x097F],
49
+ // Devanagari
50
+ [0xA8E0, 0xA8FF] // Devanagari Extended
51
+ ],
52
+ thai: [[0x0E00, 0x0E7F] // Thai
53
+ ]
54
+ };
55
+
56
+ /**
57
+ * Reference characters for font metrics by script
58
+ */
59
+ const SCRIPT_REFERENCE_CHARS = {
60
+ latin: 'M',
61
+ arabic: 'ا',
62
+ // Arabic Letter Alef
63
+ hebrew: 'ם',
64
+ // Hebrew Letter Final Mem
65
+ cjk: '中',
66
+ // Chinese character for "middle"
67
+ devanagari: 'म',
68
+ // Devanagari Letter Ma
69
+ thai: 'ก',
70
+ // Thai Letter Ko Kai
71
+ mixed: 'M',
72
+ // Fallback to Latin
73
+ unknown: 'M' // Fallback to Latin
74
+ };
75
+
76
+ /**
77
+ * Script-specific fallback proportions for font metrics
78
+ */
79
+ const SCRIPT_METRICS = {
80
+ latin: {
81
+ ascentRatio: 0.91,
82
+ descentRatio: 0.21,
83
+ actualAscentRatio: 0.716,
84
+ actualDescentRatio: 0.0
85
+ },
86
+ arabic: {
87
+ ascentRatio: 0.85,
88
+ // Arabic fonts typically have lower ascenders
89
+ descentRatio: 0.30,
90
+ // But deeper descenders for diacritics
91
+ actualAscentRatio: 0.65,
92
+ actualDescentRatio: 0.25
93
+ },
94
+ hebrew: {
95
+ ascentRatio: 0.88,
96
+ descentRatio: 0.25,
97
+ actualAscentRatio: 0.70,
98
+ actualDescentRatio: 0.15
99
+ },
100
+ cjk: {
101
+ ascentRatio: 0.88,
102
+ // CJK fonts are more square
103
+ descentRatio: 0.12,
104
+ actualAscentRatio: 0.80,
105
+ actualDescentRatio: 0.10
106
+ },
107
+ devanagari: {
108
+ ascentRatio: 1.0,
109
+ // Devanagari has tall ascenders
110
+ descentRatio: 0.25,
111
+ actualAscentRatio: 0.85,
112
+ actualDescentRatio: 0.15
113
+ },
114
+ thai: {
115
+ ascentRatio: 0.95,
116
+ // Thai has tall ascenders
117
+ descentRatio: 0.30,
118
+ // And some descenders
119
+ actualAscentRatio: 0.75,
120
+ actualDescentRatio: 0.20
121
+ },
122
+ mixed: {
123
+ ascentRatio: 0.91,
124
+ descentRatio: 0.21,
125
+ actualAscentRatio: 0.716,
126
+ actualDescentRatio: 0.0
127
+ },
128
+ unknown: {
129
+ ascentRatio: 0.91,
130
+ descentRatio: 0.21,
131
+ actualAscentRatio: 0.716,
132
+ actualDescentRatio: 0.0
133
+ }
134
+ };
135
+
136
+ /**
137
+ * Detect the primary script of a text string
138
+ */
139
+ function detectScript(text) {
140
+ if (!text || text.length === 0) return 'unknown';
141
+ const scriptCounts = {
142
+ latin: 0,
143
+ arabic: 0,
144
+ hebrew: 0,
145
+ cjk: 0,
146
+ devanagari: 0,
147
+ thai: 0,
148
+ mixed: 0,
149
+ unknown: 0
150
+ };
151
+ for (const char of text) {
152
+ const codePoint = char.codePointAt(0);
153
+ if (codePoint === undefined) continue;
154
+ let detected = false;
155
+ for (const [script, ranges] of Object.entries(SCRIPT_RANGES)) {
156
+ for (const [start, end] of ranges) {
157
+ if (codePoint >= start && codePoint <= end) {
158
+ scriptCounts[script]++;
159
+ detected = true;
160
+ break;
161
+ }
162
+ }
163
+ if (detected) break;
164
+ }
165
+ if (!detected) {
166
+ scriptCounts.unknown++;
167
+ }
168
+ }
169
+
170
+ // Find the script with the highest count
171
+ const entries = Object.entries(scriptCounts);
172
+ entries.sort((a, b) => b[1] - a[1]);
173
+ const [topScript, topCount] = entries[0];
174
+ const [secondScript, secondCount] = entries[1];
175
+
176
+ // If we have significant counts in multiple scripts, consider it mixed
177
+ if (topCount > 0 && secondCount > topCount * 0.3) {
178
+ return 'mixed';
179
+ }
180
+ return topScript === 'unknown' && topCount === 0 ? 'latin' : topScript;
181
+ }
182
+
183
+ /**
184
+ * Get reference character for a given script
185
+ */
186
+ function getScriptReferenceChar(script) {
187
+ return SCRIPT_REFERENCE_CHARS[script];
188
+ }
189
+
190
+ /**
191
+ * Get script-specific metric ratios
192
+ */
193
+ function getScriptMetrics(script) {
194
+ return SCRIPT_METRICS[script];
195
+ }
196
+
197
+ /**
198
+ * Detect script for a single grapheme/character
199
+ */
200
+ function detectGraphemeScript(grapheme) {
201
+ return detectScript(grapheme);
202
+ }
203
+
204
+ /**
205
+ * Check if text contains complex script characteristics
206
+ */
207
+ function isComplexScript(script) {
208
+ return ['arabic', 'hebrew', 'devanagari', 'thai'].includes(script);
209
+ }
210
+
211
+ export { SCRIPT_METRICS, SCRIPT_REFERENCE_CHARS, detectGraphemeScript, detectScript, getScriptMetrics, getScriptReferenceChar, isComplexScript };
212
+ //# sourceMappingURL=scriptUtils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scriptUtils.mjs","sources":["../../../src/text/scriptUtils.ts"],"sourcesContent":["/**\n * Script Detection and Font Metrics Utilities\n * \n * Provides script-aware text measurement for improved bounding box calculations\n * across different writing systems like Arabic, Latin, CJK, etc.\n */\n\nexport type ScriptType = 'latin' | 'arabic' | 'hebrew' | 'cjk' | 'devanagari' | 'thai' | 'mixed' | 'unknown';\n\n/**\n * Unicode ranges for different scripts\n */\nconst SCRIPT_RANGES = {\n latin: [\n [0x0000, 0x007F], // Basic Latin\n [0x0080, 0x00FF], // Latin-1 Supplement\n [0x0100, 0x017F], // Latin Extended-A\n [0x0180, 0x024F], // Latin Extended-B\n [0x1E00, 0x1EFF], // Latin Extended Additional\n ],\n arabic: [\n [0x0600, 0x06FF], // Arabic\n [0x0750, 0x077F], // Arabic Supplement\n [0x08A0, 0x08FF], // Arabic Extended-A\n [0xFB50, 0xFDFF], // Arabic Presentation Forms-A\n [0xFE70, 0xFEFF], // Arabic Presentation Forms-B\n ],\n hebrew: [\n [0x0590, 0x05FF], // Hebrew\n [0xFB1D, 0xFB4F], // Hebrew Presentation Forms\n ],\n cjk: [\n [0x2E80, 0x2EFF], // CJK Radicals Supplement\n [0x3000, 0x303F], // CJK Symbols and Punctuation\n [0x3400, 0x4DBF], // CJK Extension A\n [0x4E00, 0x9FFF], // CJK Unified Ideographs\n [0xF900, 0xFAFF], // CJK Compatibility Ideographs\n [0x20000, 0x2A6DF], // CJK Extension B\n ],\n devanagari: [\n [0x0900, 0x097F], // Devanagari\n [0xA8E0, 0xA8FF], // Devanagari Extended\n ],\n thai: [\n [0x0E00, 0x0E7F], // Thai\n ],\n};\n\n/**\n * Reference characters for font metrics by script\n */\nexport const SCRIPT_REFERENCE_CHARS = {\n latin: 'M',\n arabic: 'ا', // Arabic Letter Alef\n hebrew: 'ם', // Hebrew Letter Final Mem\n cjk: '中', // Chinese character for \"middle\"\n devanagari: 'म', // Devanagari Letter Ma\n thai: 'ก', // Thai Letter Ko Kai\n mixed: 'M', // Fallback to Latin\n unknown: 'M', // Fallback to Latin\n} as const;\n\n/**\n * Script-specific fallback proportions for font metrics\n */\nexport const SCRIPT_METRICS = {\n latin: {\n ascentRatio: 0.91,\n descentRatio: 0.21,\n actualAscentRatio: 0.716,\n actualDescentRatio: 0.0,\n },\n arabic: {\n ascentRatio: 0.85, // Arabic fonts typically have lower ascenders\n descentRatio: 0.30, // But deeper descenders for diacritics\n actualAscentRatio: 0.65,\n actualDescentRatio: 0.25,\n },\n hebrew: {\n ascentRatio: 0.88,\n descentRatio: 0.25,\n actualAscentRatio: 0.70,\n actualDescentRatio: 0.15,\n },\n cjk: {\n ascentRatio: 0.88, // CJK fonts are more square\n descentRatio: 0.12,\n actualAscentRatio: 0.80,\n actualDescentRatio: 0.10,\n },\n devanagari: {\n ascentRatio: 1.0, // Devanagari has tall ascenders\n descentRatio: 0.25,\n actualAscentRatio: 0.85,\n actualDescentRatio: 0.15,\n },\n thai: {\n ascentRatio: 0.95, // Thai has tall ascenders\n descentRatio: 0.30, // And some descenders\n actualAscentRatio: 0.75,\n actualDescentRatio: 0.20,\n },\n mixed: {\n ascentRatio: 0.91,\n descentRatio: 0.21,\n actualAscentRatio: 0.716,\n actualDescentRatio: 0.0,\n },\n unknown: {\n ascentRatio: 0.91,\n descentRatio: 0.21,\n actualAscentRatio: 0.716,\n actualDescentRatio: 0.0,\n },\n} as const;\n\n/**\n * Detect the primary script of a text string\n */\nexport function detectScript(text: string): ScriptType {\n if (!text || text.length === 0) return 'unknown';\n\n const scriptCounts: Record<ScriptType, number> = {\n latin: 0,\n arabic: 0,\n hebrew: 0,\n cjk: 0,\n devanagari: 0,\n thai: 0,\n mixed: 0,\n unknown: 0,\n };\n\n for (const char of text) {\n const codePoint = char.codePointAt(0);\n if (codePoint === undefined) continue;\n\n let detected = false;\n \n for (const [script, ranges] of Object.entries(SCRIPT_RANGES)) {\n for (const [start, end] of ranges) {\n if (codePoint >= start && codePoint <= end) {\n scriptCounts[script as ScriptType]++;\n detected = true;\n break;\n }\n }\n if (detected) break;\n }\n\n if (!detected) {\n scriptCounts.unknown++;\n }\n }\n\n // Find the script with the highest count\n const entries = Object.entries(scriptCounts) as [ScriptType, number][];\n entries.sort((a, b) => b[1] - a[1]);\n\n const [topScript, topCount] = entries[0];\n const [secondScript, secondCount] = entries[1];\n\n // If we have significant counts in multiple scripts, consider it mixed\n if (topCount > 0 && secondCount > topCount * 0.3) {\n return 'mixed';\n }\n\n return topScript === 'unknown' && topCount === 0 ? 'latin' : topScript;\n}\n\n/**\n * Get reference character for a given script\n */\nexport function getScriptReferenceChar(script: ScriptType): string {\n return SCRIPT_REFERENCE_CHARS[script];\n}\n\n/**\n * Get script-specific metric ratios\n */\nexport function getScriptMetrics(script: ScriptType) {\n return SCRIPT_METRICS[script];\n}\n\n/**\n * Detect script for a single grapheme/character\n */\nexport function detectGraphemeScript(grapheme: string): ScriptType {\n return detectScript(grapheme);\n}\n\n/**\n * Check if text contains complex script characteristics\n */\nexport function isComplexScript(script: ScriptType): boolean {\n return ['arabic', 'hebrew', 'devanagari', 'thai'].includes(script);\n}\n\n/**\n * Check if script requires special glyph shaping\n */\nexport function requiresGlyphShaping(script: ScriptType): boolean {\n return ['arabic', 'devanagari', 'thai'].includes(script);\n}\n\n/**\n * Get optimal sample text for measuring font metrics\n */\nexport function getSampleTextForScript(script: ScriptType): string {\n const samples = {\n latin: 'AaBbCcMmWwXxYyZz',\n arabic: 'أابتجحدرسعفقلمنهويء',\n hebrew: 'אבגדהוחטיכלמנעפקרשת',\n cjk: '中文字体测试样本',\n devanagari: 'अआइईउऊएऐओऔकगचजट',\n thai: 'กขคงจชดตนบปพมยรลวสหอฮ',\n mixed: 'AaBbCcMmWwXxYyZz',\n unknown: 'AaBbCcMmWwXxYyZz',\n };\n \n return samples[script];\n}"],"names":["SCRIPT_RANGES","latin","arabic","hebrew","cjk","devanagari","thai","SCRIPT_REFERENCE_CHARS","mixed","unknown","SCRIPT_METRICS","ascentRatio","descentRatio","actualAscentRatio","actualDescentRatio","detectScript","text","length","scriptCounts","char","codePoint","codePointAt","undefined","detected","script","ranges","Object","entries","start","end","sort","a","b","topScript","topCount","secondScript","secondCount","getScriptReferenceChar","getScriptMetrics","detectGraphemeScript","grapheme","isComplexScript","includes"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;;AAIA;AACA;AACA;AACA,MAAMA,aAAa,GAAG;AACpBC,EAAAA,KAAK,EAAE,CACL,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;EAClB,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;EAClB,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;EAClB,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;AAClB,EAAA,CAAC,MAAM,EAAE,MAAM,CAAC;GACjB;AACDC,EAAAA,MAAM,EAAE,CACN,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;EAClB,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;EAClB,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;EAClB,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;AAClB,EAAA,CAAC,MAAM,EAAE,MAAM,CAAC;GACjB;AACDC,EAAAA,MAAM,EAAE,CACN,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;AAClB,EAAA,CAAC,MAAM,EAAE,MAAM,CAAC;GACjB;AACDC,EAAAA,GAAG,EAAE,CACH,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;EAClB,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;EAClB,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;EAClB,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;EAClB,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;AAClB,EAAA,CAAC,OAAO,EAAE,OAAO,CAAC;GACnB;AACDC,EAAAA,UAAU,EAAE,CACV,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;AAClB,EAAA,CAAC,MAAM,EAAE,MAAM,CAAC;GACjB;AACDC,EAAAA,IAAI,EAAE,CACJ,CAAC,MAAM,EAAE,MAAM,CAAC;AAAE;AAEtB,CAAC;;AAED;AACA;AACA;AACO,MAAMC,sBAAsB,GAAG;AACpCN,EAAAA,KAAK,EAAE,GAAG;AACVC,EAAAA,MAAM,EAAE,GAAG;AAAE;AACbC,EAAAA,MAAM,EAAE,GAAG;AAAE;AACbC,EAAAA,GAAG,EAAE,GAAG;AAAE;AACVC,EAAAA,UAAU,EAAE,GAAG;AAAE;AACjBC,EAAAA,IAAI,EAAE,GAAG;AAAE;AACXE,EAAAA,KAAK,EAAE,GAAG;AAAE;EACZC,OAAO,EAAE,GAAG;AACd;;AAEA;AACA;AACA;AACO,MAAMC,cAAc,GAAG;AAC5BT,EAAAA,KAAK,EAAE;AACLU,IAAAA,WAAW,EAAE,IAAI;AACjBC,IAAAA,YAAY,EAAE,IAAI;AAClBC,IAAAA,iBAAiB,EAAE,KAAK;AACxBC,IAAAA,kBAAkB,EAAE;GACrB;AACDZ,EAAAA,MAAM,EAAE;AACNS,IAAAA,WAAW,EAAE,IAAI;AAAE;AACnBC,IAAAA,YAAY,EAAE,IAAI;AAAE;AACpBC,IAAAA,iBAAiB,EAAE,IAAI;AACvBC,IAAAA,kBAAkB,EAAE;GACrB;AACDX,EAAAA,MAAM,EAAE;AACNQ,IAAAA,WAAW,EAAE,IAAI;AACjBC,IAAAA,YAAY,EAAE,IAAI;AAClBC,IAAAA,iBAAiB,EAAE,IAAI;AACvBC,IAAAA,kBAAkB,EAAE;GACrB;AACDV,EAAAA,GAAG,EAAE;AACHO,IAAAA,WAAW,EAAE,IAAI;AAAE;AACnBC,IAAAA,YAAY,EAAE,IAAI;AAClBC,IAAAA,iBAAiB,EAAE,IAAI;AACvBC,IAAAA,kBAAkB,EAAE;GACrB;AACDT,EAAAA,UAAU,EAAE;AACVM,IAAAA,WAAW,EAAE,GAAG;AAAE;AAClBC,IAAAA,YAAY,EAAE,IAAI;AAClBC,IAAAA,iBAAiB,EAAE,IAAI;AACvBC,IAAAA,kBAAkB,EAAE;GACrB;AACDR,EAAAA,IAAI,EAAE;AACJK,IAAAA,WAAW,EAAE,IAAI;AAAE;AACnBC,IAAAA,YAAY,EAAE,IAAI;AAAE;AACpBC,IAAAA,iBAAiB,EAAE,IAAI;AACvBC,IAAAA,kBAAkB,EAAE;GACrB;AACDN,EAAAA,KAAK,EAAE;AACLG,IAAAA,WAAW,EAAE,IAAI;AACjBC,IAAAA,YAAY,EAAE,IAAI;AAClBC,IAAAA,iBAAiB,EAAE,KAAK;AACxBC,IAAAA,kBAAkB,EAAE;GACrB;AACDL,EAAAA,OAAO,EAAE;AACPE,IAAAA,WAAW,EAAE,IAAI;AACjBC,IAAAA,YAAY,EAAE,IAAI;AAClBC,IAAAA,iBAAiB,EAAE,KAAK;AACxBC,IAAAA,kBAAkB,EAAE;AACtB;AACF;;AAEA;AACA;AACA;AACO,SAASC,YAAYA,CAACC,IAAY,EAAc;EACrD,IAAI,CAACA,IAAI,IAAIA,IAAI,CAACC,MAAM,KAAK,CAAC,EAAE,OAAO,SAAS;AAEhD,EAAA,MAAMC,YAAwC,GAAG;AAC/CjB,IAAAA,KAAK,EAAE,CAAC;AACRC,IAAAA,MAAM,EAAE,CAAC;AACTC,IAAAA,MAAM,EAAE,CAAC;AACTC,IAAAA,GAAG,EAAE,CAAC;AACNC,IAAAA,UAAU,EAAE,CAAC;AACbC,IAAAA,IAAI,EAAE,CAAC;AACPE,IAAAA,KAAK,EAAE,CAAC;AACRC,IAAAA,OAAO,EAAE;GACV;AAED,EAAA,KAAK,MAAMU,IAAI,IAAIH,IAAI,EAAE;AACvB,IAAA,MAAMI,SAAS,GAAGD,IAAI,CAACE,WAAW,CAAC,CAAC,CAAC;IACrC,IAAID,SAAS,KAAKE,SAAS,EAAE;IAE7B,IAAIC,QAAQ,GAAG,KAAK;AAEpB,IAAA,KAAK,MAAM,CAACC,MAAM,EAAEC,MAAM,CAAC,IAAIC,MAAM,CAACC,OAAO,CAAC3B,aAAa,CAAC,EAAE;MAC5D,KAAK,MAAM,CAAC4B,KAAK,EAAEC,GAAG,CAAC,IAAIJ,MAAM,EAAE;AACjC,QAAA,IAAIL,SAAS,IAAIQ,KAAK,IAAIR,SAAS,IAAIS,GAAG,EAAE;UAC1CX,YAAY,CAACM,MAAM,CAAe,EAAE;AACpCD,UAAAA,QAAQ,GAAG,IAAI;AACf,UAAA;AACF,QAAA;AACF,MAAA;AACA,MAAA,IAAIA,QAAQ,EAAE;AAChB,IAAA;IAEA,IAAI,CAACA,QAAQ,EAAE;MACbL,YAAY,CAACT,OAAO,EAAE;AACxB,IAAA;AACF,EAAA;;AAEA;AACA,EAAA,MAAMkB,OAAO,GAAGD,MAAM,CAACC,OAAO,CAACT,YAAY,CAA2B;AACtES,EAAAA,OAAO,CAACG,IAAI,CAAC,CAACC,CAAC,EAAEC,CAAC,KAAKA,CAAC,CAAC,CAAC,CAAC,GAAGD,CAAC,CAAC,CAAC,CAAC,CAAC;EAEnC,MAAM,CAACE,SAAS,EAAEC,QAAQ,CAAC,GAAGP,OAAO,CAAC,CAAC,CAAC;EACxC,MAAM,CAACQ,YAAY,EAAEC,WAAW,CAAC,GAAGT,OAAO,CAAC,CAAC,CAAC;;AAE9C;EACA,IAAIO,QAAQ,GAAG,CAAC,IAAIE,WAAW,GAAGF,QAAQ,GAAG,GAAG,EAAE;AAChD,IAAA,OAAO,OAAO;AAChB,EAAA;EAEA,OAAOD,SAAS,KAAK,SAAS,IAAIC,QAAQ,KAAK,CAAC,GAAG,OAAO,GAAGD,SAAS;AACxE;;AAEA;AACA;AACA;AACO,SAASI,sBAAsBA,CAACb,MAAkB,EAAU;EACjE,OAAOjB,sBAAsB,CAACiB,MAAM,CAAC;AACvC;;AAEA;AACA;AACA;AACO,SAASc,gBAAgBA,CAACd,MAAkB,EAAE;EACnD,OAAOd,cAAc,CAACc,MAAM,CAAC;AAC/B;;AAEA;AACA;AACA;AACO,SAASe,oBAAoBA,CAACC,QAAgB,EAAc;EACjE,OAAOzB,YAAY,CAACyB,QAAQ,CAAC;AAC/B;;AAEA;AACA;AACA;AACO,SAASC,eAAeA,CAACjB,MAAkB,EAAW;AAC3D,EAAA,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,CAACkB,QAAQ,CAAClB,MAAM,CAAC;AACpE;;;;"}
@@ -0,0 +1,70 @@
1
+ import type { XY } from '../../Point';
2
+ export interface CornerRadiusOptions {
3
+ /**
4
+ * Corner radius value
5
+ */
6
+ radius: number;
7
+ /**
8
+ * Whether to apply radius as percentage of the smallest dimension
9
+ */
10
+ radiusAsPercentage?: boolean;
11
+ }
12
+ export interface RoundedCornerPoint {
13
+ /**
14
+ * Original corner point
15
+ */
16
+ corner: XY;
17
+ /**
18
+ * Start point of the rounded corner arc
19
+ */
20
+ start: XY;
21
+ /**
22
+ * End point of the rounded corner arc
23
+ */
24
+ end: XY;
25
+ /**
26
+ * First control point for bezier curve
27
+ */
28
+ cp1: XY;
29
+ /**
30
+ * Second control point for bezier curve
31
+ */
32
+ cp2: XY;
33
+ /**
34
+ * Actual radius used (may be different from requested if constrained)
35
+ */
36
+ actualRadius: number;
37
+ }
38
+ /**
39
+ * Calculate the distance between two points
40
+ */
41
+ export declare function pointDistance(p1: XY, p2: XY): number;
42
+ /**
43
+ * Normalize a vector
44
+ */
45
+ export declare function normalizeVector(vector: XY): XY;
46
+ /**
47
+ * Calculate the angle between two vectors
48
+ */
49
+ export declare function angleBetweenVectors(v1: XY, v2: XY): number;
50
+ /**
51
+ * Get the maximum allowed radius for a corner based on adjacent edge lengths
52
+ */
53
+ export declare function getMaxRadius(prevPoint: XY, currentPoint: XY, nextPoint: XY): number;
54
+ /**
55
+ * Calculate rounded corner data for a single corner
56
+ */
57
+ export declare function calculateRoundedCorner(prevPoint: XY, currentPoint: XY, nextPoint: XY, radius: number): RoundedCornerPoint;
58
+ /**
59
+ * Apply corner radius to a polygon defined by points
60
+ */
61
+ export declare function applyCornerRadiusToPolygon(points: XY[], radius: number, radiusAsPercentage?: boolean): RoundedCornerPoint[];
62
+ /**
63
+ * Render a rounded polygon to a canvas context
64
+ */
65
+ export declare function renderRoundedPolygon(ctx: CanvasRenderingContext2D, roundedCorners: RoundedCornerPoint[], closed?: boolean): void;
66
+ /**
67
+ * Generate SVG path data for a rounded polygon
68
+ */
69
+ export declare function generateRoundedPolygonPath(roundedCorners: RoundedCornerPoint[], closed?: boolean): string;
70
+ //# sourceMappingURL=cornerRadius.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cornerRadius.d.ts","sourceRoot":"","sources":["../../../../src/util/misc/cornerRadius.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAItC,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,MAAM,EAAE,EAAE,CAAC;IACX;;OAEG;IACH,KAAK,EAAE,EAAE,CAAC;IACV;;OAEG;IACH,GAAG,EAAE,EAAE,CAAC;IACR;;OAEG;IACH,GAAG,EAAE,EAAE,CAAC;IACR;;OAEG;IACH,GAAG,EAAE,EAAE,CAAC;IACR;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,CAI9C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,CAI1D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,EAAE,EACb,YAAY,EAAE,EAAE,EAChB,SAAS,EAAE,EAAE,GACZ,MAAM,CAIR;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,EAAE,EACb,YAAY,EAAE,EAAE,EAChB,SAAS,EAAE,EAAE,EACb,MAAM,EAAE,MAAM,GACb,kBAAkB,CAoDpB;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,EAAE,EAAE,EACZ,MAAM,EAAE,MAAM,EACd,kBAAkB,UAAQ,GACzB,kBAAkB,EAAE,CAuCtB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,wBAAwB,EAC7B,cAAc,EAAE,kBAAkB,EAAE,EACpC,MAAM,UAAO,QAkCd;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,cAAc,EAAE,kBAAkB,EAAE,EACpC,MAAM,UAAO,GACZ,MAAM,CA8BR"}
@@ -0,0 +1,2 @@
1
+ import{kRect as t}from"../../constants.min.mjs";function n(t,n){return Math.sqrt(Math.pow(n.x-t.x,2)+Math.pow(n.y-t.y,2))}function e(t){const n=Math.sqrt(t.x*t.x+t.y*t.y);return 0===n?{x:0,y:0}:{x:t.x/n,y:t.y/n}}function o(t,e,o){const r=n(t,e),x=n(e,o);return Math.min(r,x)/2}function r(n,r,x,y){const h={x:r.x-n.x,y:r.y-n.y},a={x:x.x-r.x,y:x.y-r.y},s=e(h),c=e(a),l=o(n,r,x),i=Math.min(y,l),p={x:r.x-s.x*i,y:r.y-s.y*i},u={x:r.x+c.x*i,y:r.y+c.y*i},g=i*t;return{corner:r,start:p,end:u,cp1:{x:p.x+s.x*g,y:p.y+s.y*g},cp2:{x:u.x-c.x*g,y:u.y-c.y*g},actualRadius:i}}function x(t,n){let e=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(t.length<3)throw new Error("Polygon must have at least 3 points");let o=n;if(e){const e=Math.min(...t.map(t=>t.x)),r=Math.max(...t.map(t=>t.x)),x=Math.min(...t.map(t=>t.y)),y=r-e,h=Math.max(...t.map(t=>t.y))-x;o=n/100*Math.min(y,h)}const x=[];for(let n=0;n<t.length;n++){const e=(n-1+t.length)%t.length,y=(n+1)%t.length,h=r(t[e],t[n],t[y],o);x.push(h)}return x}function y(t,n){let e=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if(0===n.length)return;t.beginPath();const o=n[0];t.moveTo(o.start.x,o.start.y);for(let o=0;o<n.length;o++){const r=n[o],x=n[(o+1)%n.length];t.bezierCurveTo(r.cp1.x,r.cp1.y,r.cp2.x,r.cp2.y,r.end.x,r.end.y),(o<n.length-1||e)&&t.lineTo(x.start.x,x.start.y)}e&&t.closePath()}function h(t){let n=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];if(0===t.length)return"";const e=[],o=t[0];e.push(`M ${o.start.x} ${o.start.y}`);for(let o=0;o<t.length;o++){const r=t[o],x=t[(o+1)%t.length];e.push(`C ${r.cp1.x} ${r.cp1.y} ${r.cp2.x} ${r.cp2.y} ${r.end.x} ${r.end.y}`),(o<t.length-1||n)&&e.push(`L ${x.start.x} ${x.start.y}`)}return n&&e.push("Z"),e.join(" ")}export{x as applyCornerRadiusToPolygon,r as calculateRoundedCorner,h as generateRoundedPolygonPath,o as getMaxRadius,e as normalizeVector,n as pointDistance,y as renderRoundedPolygon};
2
+ //# sourceMappingURL=cornerRadius.min.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cornerRadius.min.mjs","sources":["../../../../src/util/misc/cornerRadius.ts"],"sourcesContent":["import type { XY } from '../../Point';\nimport { Point } from '../../Point';\nimport { kRect } from '../../constants';\n\nexport interface CornerRadiusOptions {\n /**\n * Corner radius value\n */\n radius: number;\n /**\n * Whether to apply radius as percentage of the smallest dimension\n */\n radiusAsPercentage?: boolean;\n}\n\nexport interface RoundedCornerPoint {\n /**\n * Original corner point\n */\n corner: XY;\n /**\n * Start point of the rounded corner arc\n */\n start: XY;\n /**\n * End point of the rounded corner arc\n */\n end: XY;\n /**\n * First control point for bezier curve\n */\n cp1: XY;\n /**\n * Second control point for bezier curve\n */\n cp2: XY;\n /**\n * Actual radius used (may be different from requested if constrained)\n */\n actualRadius: number;\n}\n\n/**\n * Calculate the distance between two points\n */\nexport function pointDistance(p1: XY, p2: XY): number {\n return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));\n}\n\n/**\n * Normalize a vector\n */\nexport function normalizeVector(vector: XY): XY {\n const length = Math.sqrt(vector.x * vector.x + vector.y * vector.y);\n if (length === 0) return { x: 0, y: 0 };\n return { x: vector.x / length, y: vector.y / length };\n}\n\n/**\n * Calculate the angle between two vectors\n */\nexport function angleBetweenVectors(v1: XY, v2: XY): number {\n const dot = v1.x * v2.x + v1.y * v2.y;\n const det = v1.x * v2.y - v1.y * v2.x;\n return Math.atan2(det, dot);\n}\n\n/**\n * Get the maximum allowed radius for a corner based on adjacent edge lengths\n */\nexport function getMaxRadius(\n prevPoint: XY,\n currentPoint: XY,\n nextPoint: XY,\n): number {\n const dist1 = pointDistance(prevPoint, currentPoint);\n const dist2 = pointDistance(currentPoint, nextPoint);\n return Math.min(dist1, dist2) / 2;\n}\n\n/**\n * Calculate rounded corner data for a single corner\n */\nexport function calculateRoundedCorner(\n prevPoint: XY,\n currentPoint: XY,\n nextPoint: XY,\n radius: number,\n): RoundedCornerPoint {\n // Calculate edge vectors\n const edge1 = {\n x: currentPoint.x - prevPoint.x,\n y: currentPoint.y - prevPoint.y,\n };\n const edge2 = {\n x: nextPoint.x - currentPoint.x,\n y: nextPoint.y - currentPoint.y,\n };\n\n // Normalize edge vectors\n const norm1 = normalizeVector(edge1);\n const norm2 = normalizeVector(edge2);\n\n // Calculate the maximum allowed radius\n const maxRadius = getMaxRadius(prevPoint, currentPoint, nextPoint);\n const actualRadius = Math.min(radius, maxRadius);\n\n // Calculate start and end points of the rounded corner\n const startPoint = {\n x: currentPoint.x - norm1.x * actualRadius,\n y: currentPoint.y - norm1.y * actualRadius,\n };\n\n const endPoint = {\n x: currentPoint.x + norm2.x * actualRadius,\n y: currentPoint.y + norm2.y * actualRadius,\n };\n\n // Calculate control points for bezier curve\n // Using the magic number kRect for optimal circular approximation\n const controlOffset = actualRadius * kRect;\n\n const cp1 = {\n x: startPoint.x + norm1.x * controlOffset,\n y: startPoint.y + norm1.y * controlOffset,\n };\n\n const cp2 = {\n x: endPoint.x - norm2.x * controlOffset,\n y: endPoint.y - norm2.y * controlOffset,\n };\n\n return {\n corner: currentPoint,\n start: startPoint,\n end: endPoint,\n cp1,\n cp2,\n actualRadius,\n };\n}\n\n/**\n * Apply corner radius to a polygon defined by points\n */\nexport function applyCornerRadiusToPolygon(\n points: XY[],\n radius: number,\n radiusAsPercentage = false,\n): RoundedCornerPoint[] {\n if (points.length < 3) {\n throw new Error('Polygon must have at least 3 points');\n }\n\n // Calculate bounding box if radius is percentage-based\n let actualRadius = radius;\n if (radiusAsPercentage) {\n const minX = Math.min(...points.map((p) => p.x));\n const maxX = Math.max(...points.map((p) => p.x));\n const minY = Math.min(...points.map((p) => p.y));\n const maxY = Math.max(...points.map((p) => p.y));\n const width = maxX - minX;\n const height = maxY - minY;\n const minDimension = Math.min(width, height);\n actualRadius = (radius / 100) * minDimension;\n }\n\n const roundedCorners: RoundedCornerPoint[] = [];\n\n for (let i = 0; i < points.length; i++) {\n const prevIndex = (i - 1 + points.length) % points.length;\n const nextIndex = (i + 1) % points.length;\n\n const prevPoint = points[prevIndex];\n const currentPoint = points[i];\n const nextPoint = points[nextIndex];\n\n const roundedCorner = calculateRoundedCorner(\n prevPoint,\n currentPoint,\n nextPoint,\n actualRadius,\n );\n\n roundedCorners.push(roundedCorner);\n }\n\n return roundedCorners;\n}\n\n/**\n * Render a rounded polygon to a canvas context\n */\nexport function renderRoundedPolygon(\n ctx: CanvasRenderingContext2D,\n roundedCorners: RoundedCornerPoint[],\n closed = true,\n) {\n if (roundedCorners.length === 0) return;\n\n ctx.beginPath();\n\n // Start at the first corner's start point\n const firstCorner = roundedCorners[0];\n ctx.moveTo(firstCorner.start.x, firstCorner.start.y);\n\n for (let i = 0; i < roundedCorners.length; i++) {\n const corner = roundedCorners[i];\n const nextIndex = (i + 1) % roundedCorners.length;\n const nextCorner = roundedCorners[nextIndex];\n\n // Draw the rounded corner using bezier curve\n ctx.bezierCurveTo(\n corner.cp1.x,\n corner.cp1.y,\n corner.cp2.x,\n corner.cp2.y,\n corner.end.x,\n corner.end.y,\n );\n\n // Draw line to next corner's start point (if not the last segment in open path)\n if (i < roundedCorners.length - 1 || closed) {\n ctx.lineTo(nextCorner.start.x, nextCorner.start.y);\n }\n }\n\n if (closed) {\n ctx.closePath();\n }\n}\n\n/**\n * Generate SVG path data for a rounded polygon\n */\nexport function generateRoundedPolygonPath(\n roundedCorners: RoundedCornerPoint[],\n closed = true,\n): string {\n if (roundedCorners.length === 0) return '';\n\n const pathData: string[] = [];\n const firstCorner = roundedCorners[0];\n\n // Move to first corner's start point\n pathData.push(`M ${firstCorner.start.x} ${firstCorner.start.y}`);\n\n for (let i = 0; i < roundedCorners.length; i++) {\n const corner = roundedCorners[i];\n const nextIndex = (i + 1) % roundedCorners.length;\n const nextCorner = roundedCorners[nextIndex];\n\n // Add bezier curve for the rounded corner\n pathData.push(\n `C ${corner.cp1.x} ${corner.cp1.y} ${corner.cp2.x} ${corner.cp2.y} ${corner.end.x} ${corner.end.y}`,\n );\n\n // Add line to next corner's start point (if not the last segment in open path)\n if (i < roundedCorners.length - 1 || closed) {\n pathData.push(`L ${nextCorner.start.x} ${nextCorner.start.y}`);\n }\n }\n\n if (closed) {\n pathData.push('Z');\n }\n\n return pathData.join(' ');\n}"],"names":["pointDistance","p1","p2","Math","sqrt","pow","x","y","normalizeVector","vector","length","getMaxRadius","prevPoint","currentPoint","nextPoint","dist1","dist2","min","calculateRoundedCorner","radius","edge1","edge2","norm1","norm2","maxRadius","actualRadius","startPoint","endPoint","controlOffset","kRect","corner","start","end","cp1","cp2","applyCornerRadiusToPolygon","points","radiusAsPercentage","arguments","undefined","Error","minX","map","p","maxX","max","minY","width","height","roundedCorners","i","prevIndex","nextIndex","roundedCorner","push","renderRoundedPolygon","ctx","closed","beginPath","firstCorner","moveTo","nextCorner","bezierCurveTo","lineTo","closePath","generateRoundedPolygonPath","pathData","join"],"mappings":"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"}
@@ -0,0 +1,181 @@
1
+ import { kRect } from '../../constants.mjs';
2
+
3
+ /**
4
+ * Calculate the distance between two points
5
+ */
6
+ function pointDistance(p1, p2) {
7
+ return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
8
+ }
9
+
10
+ /**
11
+ * Normalize a vector
12
+ */
13
+ function normalizeVector(vector) {
14
+ const length = Math.sqrt(vector.x * vector.x + vector.y * vector.y);
15
+ if (length === 0) return {
16
+ x: 0,
17
+ y: 0
18
+ };
19
+ return {
20
+ x: vector.x / length,
21
+ y: vector.y / length
22
+ };
23
+ }
24
+
25
+ /**
26
+ * Get the maximum allowed radius for a corner based on adjacent edge lengths
27
+ */
28
+ function getMaxRadius(prevPoint, currentPoint, nextPoint) {
29
+ const dist1 = pointDistance(prevPoint, currentPoint);
30
+ const dist2 = pointDistance(currentPoint, nextPoint);
31
+ return Math.min(dist1, dist2) / 2;
32
+ }
33
+
34
+ /**
35
+ * Calculate rounded corner data for a single corner
36
+ */
37
+ function calculateRoundedCorner(prevPoint, currentPoint, nextPoint, radius) {
38
+ // Calculate edge vectors
39
+ const edge1 = {
40
+ x: currentPoint.x - prevPoint.x,
41
+ y: currentPoint.y - prevPoint.y
42
+ };
43
+ const edge2 = {
44
+ x: nextPoint.x - currentPoint.x,
45
+ y: nextPoint.y - currentPoint.y
46
+ };
47
+
48
+ // Normalize edge vectors
49
+ const norm1 = normalizeVector(edge1);
50
+ const norm2 = normalizeVector(edge2);
51
+
52
+ // Calculate the maximum allowed radius
53
+ const maxRadius = getMaxRadius(prevPoint, currentPoint, nextPoint);
54
+ const actualRadius = Math.min(radius, maxRadius);
55
+
56
+ // Calculate start and end points of the rounded corner
57
+ const startPoint = {
58
+ x: currentPoint.x - norm1.x * actualRadius,
59
+ y: currentPoint.y - norm1.y * actualRadius
60
+ };
61
+ const endPoint = {
62
+ x: currentPoint.x + norm2.x * actualRadius,
63
+ y: currentPoint.y + norm2.y * actualRadius
64
+ };
65
+
66
+ // Calculate control points for bezier curve
67
+ // Using the magic number kRect for optimal circular approximation
68
+ const controlOffset = actualRadius * kRect;
69
+ const cp1 = {
70
+ x: startPoint.x + norm1.x * controlOffset,
71
+ y: startPoint.y + norm1.y * controlOffset
72
+ };
73
+ const cp2 = {
74
+ x: endPoint.x - norm2.x * controlOffset,
75
+ y: endPoint.y - norm2.y * controlOffset
76
+ };
77
+ return {
78
+ corner: currentPoint,
79
+ start: startPoint,
80
+ end: endPoint,
81
+ cp1,
82
+ cp2,
83
+ actualRadius
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Apply corner radius to a polygon defined by points
89
+ */
90
+ function applyCornerRadiusToPolygon(points, radius) {
91
+ let radiusAsPercentage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
92
+ if (points.length < 3) {
93
+ throw new Error('Polygon must have at least 3 points');
94
+ }
95
+
96
+ // Calculate bounding box if radius is percentage-based
97
+ let actualRadius = radius;
98
+ if (radiusAsPercentage) {
99
+ const minX = Math.min(...points.map(p => p.x));
100
+ const maxX = Math.max(...points.map(p => p.x));
101
+ const minY = Math.min(...points.map(p => p.y));
102
+ const maxY = Math.max(...points.map(p => p.y));
103
+ const width = maxX - minX;
104
+ const height = maxY - minY;
105
+ const minDimension = Math.min(width, height);
106
+ actualRadius = radius / 100 * minDimension;
107
+ }
108
+ const roundedCorners = [];
109
+ for (let i = 0; i < points.length; i++) {
110
+ const prevIndex = (i - 1 + points.length) % points.length;
111
+ const nextIndex = (i + 1) % points.length;
112
+ const prevPoint = points[prevIndex];
113
+ const currentPoint = points[i];
114
+ const nextPoint = points[nextIndex];
115
+ const roundedCorner = calculateRoundedCorner(prevPoint, currentPoint, nextPoint, actualRadius);
116
+ roundedCorners.push(roundedCorner);
117
+ }
118
+ return roundedCorners;
119
+ }
120
+
121
+ /**
122
+ * Render a rounded polygon to a canvas context
123
+ */
124
+ function renderRoundedPolygon(ctx, roundedCorners) {
125
+ let closed = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
126
+ if (roundedCorners.length === 0) return;
127
+ ctx.beginPath();
128
+
129
+ // Start at the first corner's start point
130
+ const firstCorner = roundedCorners[0];
131
+ ctx.moveTo(firstCorner.start.x, firstCorner.start.y);
132
+ for (let i = 0; i < roundedCorners.length; i++) {
133
+ const corner = roundedCorners[i];
134
+ const nextIndex = (i + 1) % roundedCorners.length;
135
+ const nextCorner = roundedCorners[nextIndex];
136
+
137
+ // Draw the rounded corner using bezier curve
138
+ ctx.bezierCurveTo(corner.cp1.x, corner.cp1.y, corner.cp2.x, corner.cp2.y, corner.end.x, corner.end.y);
139
+
140
+ // Draw line to next corner's start point (if not the last segment in open path)
141
+ if (i < roundedCorners.length - 1 || closed) {
142
+ ctx.lineTo(nextCorner.start.x, nextCorner.start.y);
143
+ }
144
+ }
145
+ if (closed) {
146
+ ctx.closePath();
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Generate SVG path data for a rounded polygon
152
+ */
153
+ function generateRoundedPolygonPath(roundedCorners) {
154
+ let closed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
155
+ if (roundedCorners.length === 0) return '';
156
+ const pathData = [];
157
+ const firstCorner = roundedCorners[0];
158
+
159
+ // Move to first corner's start point
160
+ pathData.push(`M ${firstCorner.start.x} ${firstCorner.start.y}`);
161
+ for (let i = 0; i < roundedCorners.length; i++) {
162
+ const corner = roundedCorners[i];
163
+ const nextIndex = (i + 1) % roundedCorners.length;
164
+ const nextCorner = roundedCorners[nextIndex];
165
+
166
+ // Add bezier curve for the rounded corner
167
+ pathData.push(`C ${corner.cp1.x} ${corner.cp1.y} ${corner.cp2.x} ${corner.cp2.y} ${corner.end.x} ${corner.end.y}`);
168
+
169
+ // Add line to next corner's start point (if not the last segment in open path)
170
+ if (i < roundedCorners.length - 1 || closed) {
171
+ pathData.push(`L ${nextCorner.start.x} ${nextCorner.start.y}`);
172
+ }
173
+ }
174
+ if (closed) {
175
+ pathData.push('Z');
176
+ }
177
+ return pathData.join(' ');
178
+ }
179
+
180
+ export { applyCornerRadiusToPolygon, calculateRoundedCorner, generateRoundedPolygonPath, getMaxRadius, normalizeVector, pointDistance, renderRoundedPolygon };
181
+ //# sourceMappingURL=cornerRadius.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cornerRadius.mjs","sources":["../../../../src/util/misc/cornerRadius.ts"],"sourcesContent":["import type { XY } from '../../Point';\nimport { Point } from '../../Point';\nimport { kRect } from '../../constants';\n\nexport interface CornerRadiusOptions {\n /**\n * Corner radius value\n */\n radius: number;\n /**\n * Whether to apply radius as percentage of the smallest dimension\n */\n radiusAsPercentage?: boolean;\n}\n\nexport interface RoundedCornerPoint {\n /**\n * Original corner point\n */\n corner: XY;\n /**\n * Start point of the rounded corner arc\n */\n start: XY;\n /**\n * End point of the rounded corner arc\n */\n end: XY;\n /**\n * First control point for bezier curve\n */\n cp1: XY;\n /**\n * Second control point for bezier curve\n */\n cp2: XY;\n /**\n * Actual radius used (may be different from requested if constrained)\n */\n actualRadius: number;\n}\n\n/**\n * Calculate the distance between two points\n */\nexport function pointDistance(p1: XY, p2: XY): number {\n return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));\n}\n\n/**\n * Normalize a vector\n */\nexport function normalizeVector(vector: XY): XY {\n const length = Math.sqrt(vector.x * vector.x + vector.y * vector.y);\n if (length === 0) return { x: 0, y: 0 };\n return { x: vector.x / length, y: vector.y / length };\n}\n\n/**\n * Calculate the angle between two vectors\n */\nexport function angleBetweenVectors(v1: XY, v2: XY): number {\n const dot = v1.x * v2.x + v1.y * v2.y;\n const det = v1.x * v2.y - v1.y * v2.x;\n return Math.atan2(det, dot);\n}\n\n/**\n * Get the maximum allowed radius for a corner based on adjacent edge lengths\n */\nexport function getMaxRadius(\n prevPoint: XY,\n currentPoint: XY,\n nextPoint: XY,\n): number {\n const dist1 = pointDistance(prevPoint, currentPoint);\n const dist2 = pointDistance(currentPoint, nextPoint);\n return Math.min(dist1, dist2) / 2;\n}\n\n/**\n * Calculate rounded corner data for a single corner\n */\nexport function calculateRoundedCorner(\n prevPoint: XY,\n currentPoint: XY,\n nextPoint: XY,\n radius: number,\n): RoundedCornerPoint {\n // Calculate edge vectors\n const edge1 = {\n x: currentPoint.x - prevPoint.x,\n y: currentPoint.y - prevPoint.y,\n };\n const edge2 = {\n x: nextPoint.x - currentPoint.x,\n y: nextPoint.y - currentPoint.y,\n };\n\n // Normalize edge vectors\n const norm1 = normalizeVector(edge1);\n const norm2 = normalizeVector(edge2);\n\n // Calculate the maximum allowed radius\n const maxRadius = getMaxRadius(prevPoint, currentPoint, nextPoint);\n const actualRadius = Math.min(radius, maxRadius);\n\n // Calculate start and end points of the rounded corner\n const startPoint = {\n x: currentPoint.x - norm1.x * actualRadius,\n y: currentPoint.y - norm1.y * actualRadius,\n };\n\n const endPoint = {\n x: currentPoint.x + norm2.x * actualRadius,\n y: currentPoint.y + norm2.y * actualRadius,\n };\n\n // Calculate control points for bezier curve\n // Using the magic number kRect for optimal circular approximation\n const controlOffset = actualRadius * kRect;\n\n const cp1 = {\n x: startPoint.x + norm1.x * controlOffset,\n y: startPoint.y + norm1.y * controlOffset,\n };\n\n const cp2 = {\n x: endPoint.x - norm2.x * controlOffset,\n y: endPoint.y - norm2.y * controlOffset,\n };\n\n return {\n corner: currentPoint,\n start: startPoint,\n end: endPoint,\n cp1,\n cp2,\n actualRadius,\n };\n}\n\n/**\n * Apply corner radius to a polygon defined by points\n */\nexport function applyCornerRadiusToPolygon(\n points: XY[],\n radius: number,\n radiusAsPercentage = false,\n): RoundedCornerPoint[] {\n if (points.length < 3) {\n throw new Error('Polygon must have at least 3 points');\n }\n\n // Calculate bounding box if radius is percentage-based\n let actualRadius = radius;\n if (radiusAsPercentage) {\n const minX = Math.min(...points.map((p) => p.x));\n const maxX = Math.max(...points.map((p) => p.x));\n const minY = Math.min(...points.map((p) => p.y));\n const maxY = Math.max(...points.map((p) => p.y));\n const width = maxX - minX;\n const height = maxY - minY;\n const minDimension = Math.min(width, height);\n actualRadius = (radius / 100) * minDimension;\n }\n\n const roundedCorners: RoundedCornerPoint[] = [];\n\n for (let i = 0; i < points.length; i++) {\n const prevIndex = (i - 1 + points.length) % points.length;\n const nextIndex = (i + 1) % points.length;\n\n const prevPoint = points[prevIndex];\n const currentPoint = points[i];\n const nextPoint = points[nextIndex];\n\n const roundedCorner = calculateRoundedCorner(\n prevPoint,\n currentPoint,\n nextPoint,\n actualRadius,\n );\n\n roundedCorners.push(roundedCorner);\n }\n\n return roundedCorners;\n}\n\n/**\n * Render a rounded polygon to a canvas context\n */\nexport function renderRoundedPolygon(\n ctx: CanvasRenderingContext2D,\n roundedCorners: RoundedCornerPoint[],\n closed = true,\n) {\n if (roundedCorners.length === 0) return;\n\n ctx.beginPath();\n\n // Start at the first corner's start point\n const firstCorner = roundedCorners[0];\n ctx.moveTo(firstCorner.start.x, firstCorner.start.y);\n\n for (let i = 0; i < roundedCorners.length; i++) {\n const corner = roundedCorners[i];\n const nextIndex = (i + 1) % roundedCorners.length;\n const nextCorner = roundedCorners[nextIndex];\n\n // Draw the rounded corner using bezier curve\n ctx.bezierCurveTo(\n corner.cp1.x,\n corner.cp1.y,\n corner.cp2.x,\n corner.cp2.y,\n corner.end.x,\n corner.end.y,\n );\n\n // Draw line to next corner's start point (if not the last segment in open path)\n if (i < roundedCorners.length - 1 || closed) {\n ctx.lineTo(nextCorner.start.x, nextCorner.start.y);\n }\n }\n\n if (closed) {\n ctx.closePath();\n }\n}\n\n/**\n * Generate SVG path data for a rounded polygon\n */\nexport function generateRoundedPolygonPath(\n roundedCorners: RoundedCornerPoint[],\n closed = true,\n): string {\n if (roundedCorners.length === 0) return '';\n\n const pathData: string[] = [];\n const firstCorner = roundedCorners[0];\n\n // Move to first corner's start point\n pathData.push(`M ${firstCorner.start.x} ${firstCorner.start.y}`);\n\n for (let i = 0; i < roundedCorners.length; i++) {\n const corner = roundedCorners[i];\n const nextIndex = (i + 1) % roundedCorners.length;\n const nextCorner = roundedCorners[nextIndex];\n\n // Add bezier curve for the rounded corner\n pathData.push(\n `C ${corner.cp1.x} ${corner.cp1.y} ${corner.cp2.x} ${corner.cp2.y} ${corner.end.x} ${corner.end.y}`,\n );\n\n // Add line to next corner's start point (if not the last segment in open path)\n if (i < roundedCorners.length - 1 || closed) {\n pathData.push(`L ${nextCorner.start.x} ${nextCorner.start.y}`);\n }\n }\n\n if (closed) {\n pathData.push('Z');\n }\n\n return pathData.join(' ');\n}"],"names":["pointDistance","p1","p2","Math","sqrt","pow","x","y","normalizeVector","vector","length","getMaxRadius","prevPoint","currentPoint","nextPoint","dist1","dist2","min","calculateRoundedCorner","radius","edge1","edge2","norm1","norm2","maxRadius","actualRadius","startPoint","endPoint","controlOffset","kRect","cp1","cp2","corner","start","end","applyCornerRadiusToPolygon","points","radiusAsPercentage","arguments","undefined","Error","minX","map","p","maxX","max","minY","maxY","width","height","minDimension","roundedCorners","i","prevIndex","nextIndex","roundedCorner","push","renderRoundedPolygon","ctx","closed","beginPath","firstCorner","moveTo","nextCorner","bezierCurveTo","lineTo","closePath","generateRoundedPolygonPath","pathData","join"],"mappings":";;AA0CA;AACA;AACA;AACO,SAASA,aAAaA,CAACC,EAAM,EAAEC,EAAM,EAAU;AACpD,EAAA,OAAOC,IAAI,CAACC,IAAI,CAACD,IAAI,CAACE,GAAG,CAACH,EAAE,CAACI,CAAC,GAAGL,EAAE,CAACK,CAAC,EAAE,CAAC,CAAC,GAAGH,IAAI,CAACE,GAAG,CAACH,EAAE,CAACK,CAAC,GAAGN,EAAE,CAACM,CAAC,EAAE,CAAC,CAAC,CAAC;AACvE;;AAEA;AACA;AACA;AACO,SAASC,eAAeA,CAACC,MAAU,EAAM;EAC9C,MAAMC,MAAM,GAAGP,IAAI,CAACC,IAAI,CAACK,MAAM,CAACH,CAAC,GAAGG,MAAM,CAACH,CAAC,GAAGG,MAAM,CAACF,CAAC,GAAGE,MAAM,CAACF,CAAC,CAAC;AACnE,EAAA,IAAIG,MAAM,KAAK,CAAC,EAAE,OAAO;AAAEJ,IAAAA,CAAC,EAAE,CAAC;AAAEC,IAAAA,CAAC,EAAE;GAAG;EACvC,OAAO;AAAED,IAAAA,CAAC,EAAEG,MAAM,CAACH,CAAC,GAAGI,MAAM;AAAEH,IAAAA,CAAC,EAAEE,MAAM,CAACF,CAAC,GAAGG;GAAQ;AACvD;;AAWA;AACA;AACA;AACO,SAASC,YAAYA,CAC1BC,SAAa,EACbC,YAAgB,EAChBC,SAAa,EACL;AACR,EAAA,MAAMC,KAAK,GAAGf,aAAa,CAACY,SAAS,EAAEC,YAAY,CAAC;AACpD,EAAA,MAAMG,KAAK,GAAGhB,aAAa,CAACa,YAAY,EAAEC,SAAS,CAAC;EACpD,OAAOX,IAAI,CAACc,GAAG,CAACF,KAAK,EAAEC,KAAK,CAAC,GAAG,CAAC;AACnC;;AAEA;AACA;AACA;AACO,SAASE,sBAAsBA,CACpCN,SAAa,EACbC,YAAgB,EAChBC,SAAa,EACbK,MAAc,EACM;AACpB;AACA,EAAA,MAAMC,KAAK,GAAG;AACZd,IAAAA,CAAC,EAAEO,YAAY,CAACP,CAAC,GAAGM,SAAS,CAACN,CAAC;AAC/BC,IAAAA,CAAC,EAAEM,YAAY,CAACN,CAAC,GAAGK,SAAS,CAACL;GAC/B;AACD,EAAA,MAAMc,KAAK,GAAG;AACZf,IAAAA,CAAC,EAAEQ,SAAS,CAACR,CAAC,GAAGO,YAAY,CAACP,CAAC;AAC/BC,IAAAA,CAAC,EAAEO,SAAS,CAACP,CAAC,GAAGM,YAAY,CAACN;GAC/B;;AAED;AACA,EAAA,MAAMe,KAAK,GAAGd,eAAe,CAACY,KAAK,CAAC;AACpC,EAAA,MAAMG,KAAK,GAAGf,eAAe,CAACa,KAAK,CAAC;;AAEpC;EACA,MAAMG,SAAS,GAAGb,YAAY,CAACC,SAAS,EAAEC,YAAY,EAAEC,SAAS,CAAC;EAClE,MAAMW,YAAY,GAAGtB,IAAI,CAACc,GAAG,CAACE,MAAM,EAAEK,SAAS,CAAC;;AAEhD;AACA,EAAA,MAAME,UAAU,GAAG;IACjBpB,CAAC,EAAEO,YAAY,CAACP,CAAC,GAAGgB,KAAK,CAAChB,CAAC,GAAGmB,YAAY;IAC1ClB,CAAC,EAAEM,YAAY,CAACN,CAAC,GAAGe,KAAK,CAACf,CAAC,GAAGkB;GAC/B;AAED,EAAA,MAAME,QAAQ,GAAG;IACfrB,CAAC,EAAEO,YAAY,CAACP,CAAC,GAAGiB,KAAK,CAACjB,CAAC,GAAGmB,YAAY;IAC1ClB,CAAC,EAAEM,YAAY,CAACN,CAAC,GAAGgB,KAAK,CAAChB,CAAC,GAAGkB;GAC/B;;AAED;AACA;AACA,EAAA,MAAMG,aAAa,GAAGH,YAAY,GAAGI,KAAK;AAE1C,EAAA,MAAMC,GAAG,GAAG;IACVxB,CAAC,EAAEoB,UAAU,CAACpB,CAAC,GAAGgB,KAAK,CAAChB,CAAC,GAAGsB,aAAa;IACzCrB,CAAC,EAAEmB,UAAU,CAACnB,CAAC,GAAGe,KAAK,CAACf,CAAC,GAAGqB;GAC7B;AAED,EAAA,MAAMG,GAAG,GAAG;IACVzB,CAAC,EAAEqB,QAAQ,CAACrB,CAAC,GAAGiB,KAAK,CAACjB,CAAC,GAAGsB,aAAa;IACvCrB,CAAC,EAAEoB,QAAQ,CAACpB,CAAC,GAAGgB,KAAK,CAAChB,CAAC,GAAGqB;GAC3B;EAED,OAAO;AACLI,IAAAA,MAAM,EAAEnB,YAAY;AACpBoB,IAAAA,KAAK,EAAEP,UAAU;AACjBQ,IAAAA,GAAG,EAAEP,QAAQ;IACbG,GAAG;IACHC,GAAG;AACHN,IAAAA;GACD;AACH;;AAEA;AACA;AACA;AACO,SAASU,0BAA0BA,CACxCC,MAAY,EACZjB,MAAc,EAEQ;AAAA,EAAA,IADtBkB,kBAAkB,GAAAC,SAAA,CAAA5B,MAAA,GAAA,CAAA,IAAA4B,SAAA,CAAA,CAAA,CAAA,KAAAC,SAAA,GAAAD,SAAA,CAAA,CAAA,CAAA,GAAG,KAAK;AAE1B,EAAA,IAAIF,MAAM,CAAC1B,MAAM,GAAG,CAAC,EAAE;AACrB,IAAA,MAAM,IAAI8B,KAAK,CAAC,qCAAqC,CAAC;AACxD,EAAA;;AAEA;EACA,IAAIf,YAAY,GAAGN,MAAM;AACzB,EAAA,IAAIkB,kBAAkB,EAAE;AACtB,IAAA,MAAMI,IAAI,GAAGtC,IAAI,CAACc,GAAG,CAAC,GAAGmB,MAAM,CAACM,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACrC,CAAC,CAAC,CAAC;AAChD,IAAA,MAAMsC,IAAI,GAAGzC,IAAI,CAAC0C,GAAG,CAAC,GAAGT,MAAM,CAACM,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACrC,CAAC,CAAC,CAAC;AAChD,IAAA,MAAMwC,IAAI,GAAG3C,IAAI,CAACc,GAAG,CAAC,GAAGmB,MAAM,CAACM,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACpC,CAAC,CAAC,CAAC;AAChD,IAAA,MAAMwC,IAAI,GAAG5C,IAAI,CAAC0C,GAAG,CAAC,GAAGT,MAAM,CAACM,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACpC,CAAC,CAAC,CAAC;AAChD,IAAA,MAAMyC,KAAK,GAAGJ,IAAI,GAAGH,IAAI;AACzB,IAAA,MAAMQ,MAAM,GAAGF,IAAI,GAAGD,IAAI;IAC1B,MAAMI,YAAY,GAAG/C,IAAI,CAACc,GAAG,CAAC+B,KAAK,EAAEC,MAAM,CAAC;AAC5CxB,IAAAA,YAAY,GAAIN,MAAM,GAAG,GAAG,GAAI+B,YAAY;AAC9C,EAAA;EAEA,MAAMC,cAAoC,GAAG,EAAE;AAE/C,EAAA,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGhB,MAAM,CAAC1B,MAAM,EAAE0C,CAAC,EAAE,EAAE;AACtC,IAAA,MAAMC,SAAS,GAAG,CAACD,CAAC,GAAG,CAAC,GAAGhB,MAAM,CAAC1B,MAAM,IAAI0B,MAAM,CAAC1B,MAAM;IACzD,MAAM4C,SAAS,GAAG,CAACF,CAAC,GAAG,CAAC,IAAIhB,MAAM,CAAC1B,MAAM;AAEzC,IAAA,MAAME,SAAS,GAAGwB,MAAM,CAACiB,SAAS,CAAC;AACnC,IAAA,MAAMxC,YAAY,GAAGuB,MAAM,CAACgB,CAAC,CAAC;AAC9B,IAAA,MAAMtC,SAAS,GAAGsB,MAAM,CAACkB,SAAS,CAAC;IAEnC,MAAMC,aAAa,GAAGrC,sBAAsB,CAC1CN,SAAS,EACTC,YAAY,EACZC,SAAS,EACTW,YACF,CAAC;AAED0B,IAAAA,cAAc,CAACK,IAAI,CAACD,aAAa,CAAC;AACpC,EAAA;AAEA,EAAA,OAAOJ,cAAc;AACvB;;AAEA;AACA;AACA;AACO,SAASM,oBAAoBA,CAClCC,GAA6B,EAC7BP,cAAoC,EAEpC;AAAA,EAAA,IADAQ,MAAM,GAAArB,SAAA,CAAA5B,MAAA,GAAA,CAAA,IAAA4B,SAAA,CAAA,CAAA,CAAA,KAAAC,SAAA,GAAAD,SAAA,CAAA,CAAA,CAAA,GAAG,IAAI;AAEb,EAAA,IAAIa,cAAc,CAACzC,MAAM,KAAK,CAAC,EAAE;EAEjCgD,GAAG,CAACE,SAAS,EAAE;;AAEf;AACA,EAAA,MAAMC,WAAW,GAAGV,cAAc,CAAC,CAAC,CAAC;AACrCO,EAAAA,GAAG,CAACI,MAAM,CAACD,WAAW,CAAC5B,KAAK,CAAC3B,CAAC,EAAEuD,WAAW,CAAC5B,KAAK,CAAC1B,CAAC,CAAC;AAEpD,EAAA,KAAK,IAAI6C,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGD,cAAc,CAACzC,MAAM,EAAE0C,CAAC,EAAE,EAAE;AAC9C,IAAA,MAAMpB,MAAM,GAAGmB,cAAc,CAACC,CAAC,CAAC;IAChC,MAAME,SAAS,GAAG,CAACF,CAAC,GAAG,CAAC,IAAID,cAAc,CAACzC,MAAM;AACjD,IAAA,MAAMqD,UAAU,GAAGZ,cAAc,CAACG,SAAS,CAAC;;AAE5C;AACAI,IAAAA,GAAG,CAACM,aAAa,CACfhC,MAAM,CAACF,GAAG,CAACxB,CAAC,EACZ0B,MAAM,CAACF,GAAG,CAACvB,CAAC,EACZyB,MAAM,CAACD,GAAG,CAACzB,CAAC,EACZ0B,MAAM,CAACD,GAAG,CAACxB,CAAC,EACZyB,MAAM,CAACE,GAAG,CAAC5B,CAAC,EACZ0B,MAAM,CAACE,GAAG,CAAC3B,CACb,CAAC;;AAED;IACA,IAAI6C,CAAC,GAAGD,cAAc,CAACzC,MAAM,GAAG,CAAC,IAAIiD,MAAM,EAAE;AAC3CD,MAAAA,GAAG,CAACO,MAAM,CAACF,UAAU,CAAC9B,KAAK,CAAC3B,CAAC,EAAEyD,UAAU,CAAC9B,KAAK,CAAC1B,CAAC,CAAC;AACpD,IAAA;AACF,EAAA;AAEA,EAAA,IAAIoD,MAAM,EAAE;IACVD,GAAG,CAACQ,SAAS,EAAE;AACjB,EAAA;AACF;;AAEA;AACA;AACA;AACO,SAASC,0BAA0BA,CACxChB,cAAoC,EAE5B;AAAA,EAAA,IADRQ,MAAM,GAAArB,SAAA,CAAA5B,MAAA,GAAA,CAAA,IAAA4B,SAAA,CAAA,CAAA,CAAA,KAAAC,SAAA,GAAAD,SAAA,CAAA,CAAA,CAAA,GAAG,IAAI;AAEb,EAAA,IAAIa,cAAc,CAACzC,MAAM,KAAK,CAAC,EAAE,OAAO,EAAE;EAE1C,MAAM0D,QAAkB,GAAG,EAAE;AAC7B,EAAA,MAAMP,WAAW,GAAGV,cAAc,CAAC,CAAC,CAAC;;AAErC;AACAiB,EAAAA,QAAQ,CAACZ,IAAI,CAAC,CAAA,EAAA,EAAKK,WAAW,CAAC5B,KAAK,CAAC3B,CAAC,CAAA,CAAA,EAAIuD,WAAW,CAAC5B,KAAK,CAAC1B,CAAC,EAAE,CAAC;AAEhE,EAAA,KAAK,IAAI6C,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGD,cAAc,CAACzC,MAAM,EAAE0C,CAAC,EAAE,EAAE;AAC9C,IAAA,MAAMpB,MAAM,GAAGmB,cAAc,CAACC,CAAC,CAAC;IAChC,MAAME,SAAS,GAAG,CAACF,CAAC,GAAG,CAAC,IAAID,cAAc,CAACzC,MAAM;AACjD,IAAA,MAAMqD,UAAU,GAAGZ,cAAc,CAACG,SAAS,CAAC;;AAE5C;AACAc,IAAAA,QAAQ,CAACZ,IAAI,CACX,KAAKxB,MAAM,CAACF,GAAG,CAACxB,CAAC,CAAA,CAAA,EAAI0B,MAAM,CAACF,GAAG,CAACvB,CAAC,CAAA,CAAA,EAAIyB,MAAM,CAACD,GAAG,CAACzB,CAAC,CAAA,CAAA,EAAI0B,MAAM,CAACD,GAAG,CAACxB,CAAC,CAAA,CAAA,EAAIyB,MAAM,CAACE,GAAG,CAAC5B,CAAC,IAAI0B,MAAM,CAACE,GAAG,CAAC3B,CAAC,EACnG,CAAC;;AAED;IACA,IAAI6C,CAAC,GAAGD,cAAc,CAACzC,MAAM,GAAG,CAAC,IAAIiD,MAAM,EAAE;AAC3CS,MAAAA,QAAQ,CAACZ,IAAI,CAAC,CAAA,EAAA,EAAKO,UAAU,CAAC9B,KAAK,CAAC3B,CAAC,CAAA,CAAA,EAAIyD,UAAU,CAAC9B,KAAK,CAAC1B,CAAC,EAAE,CAAC;AAChE,IAAA;AACF,EAAA;AAEA,EAAA,IAAIoD,MAAM,EAAE;AACVS,IAAAA,QAAQ,CAACZ,IAAI,CAAC,GAAG,CAAC;AACpB,EAAA;AAEA,EAAA,OAAOY,QAAQ,CAACC,IAAI,CAAC,GAAG,CAAC;AAC3B;;;;"}
@@ -0,0 +1,10 @@
1
+ import { Polyline, SerializedPolylineProps } from './Polyline';
2
+ import type { FabricObjectProps } from './Object/types';
3
+ import type { TOptions } from '../typedefs';
4
+ import type { ObjectEvents } from '../EventTypeDefs';
5
+ export declare class CustomLine<Props extends TOptions<FabricObjectProps> = Partial<FabricObjectProps>, SProps extends SerializedPolylineProps = SerializedPolylineProps, EventSpec extends ObjectEvents = ObjectEvents> extends Polyline<Props, SProps, EventSpec> {
6
+ static type: string;
7
+ constructor(points?: [number, number, number, number], options?: Props);
8
+ static fromObject<T extends TOptions<SerializedPolylineProps>>(object: T): Promise<CustomLine<Partial<FabricObjectProps>, SerializedPolylineProps, ObjectEvents>>;
9
+ }
10
+ //# sourceMappingURL=CustomLine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomLine.d.ts","sourceRoot":"","sources":["../../../src/shapes/CustomLine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,qBAAa,UAAU,CACrB,KAAK,SAAS,QAAQ,CAAC,iBAAiB,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,EACtE,MAAM,SAAS,uBAAuB,GAAG,uBAAuB,EAChE,SAAS,SAAS,YAAY,GAAG,YAAY,CAC7C,SAAQ,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC;IAC1C,MAAM,CAAC,IAAI,SAAgB;gBAGzB,MAAM,GAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAgB,EACvD,OAAO,GAAE,KAAmB;IAU9B,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,QAAQ,CAAC,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;CAwBzE"}