apexify.js 3.2.5 → 3.3.1

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 (75) hide show
  1. package/.tsbuildinfo +1 -1
  2. package/README.md +4 -806
  3. package/change logs.md +19 -0
  4. package/dist/ai/ApexAI.d.ts +15 -6
  5. package/dist/ai/ApexAI.d.ts.map +1 -1
  6. package/dist/ai/ApexAI.js +102 -29
  7. package/dist/ai/ApexAI.js.map +1 -1
  8. package/dist/ai/buttons/tools.d.ts.map +1 -1
  9. package/dist/ai/buttons/tools.js +1 -1
  10. package/dist/ai/buttons/tools.js.map +1 -1
  11. package/dist/ai/functions/aivoice.d.ts +1 -0
  12. package/dist/ai/functions/aivoice.d.ts.map +1 -0
  13. package/dist/ai/functions/aivoice.js +2 -0
  14. package/dist/ai/functions/aivoice.js.map +1 -0
  15. package/dist/ai/functions/draw.d.ts +1 -1
  16. package/dist/ai/functions/draw.d.ts.map +1 -1
  17. package/dist/ai/functions/draw.js +12 -1
  18. package/dist/ai/functions/draw.js.map +1 -1
  19. package/dist/ai/functions/generateVoiceResponse.d.ts +1 -1
  20. package/dist/ai/functions/generateVoiceResponse.d.ts.map +1 -1
  21. package/dist/ai/functions/generateVoiceResponse.js +3 -3
  22. package/dist/ai/functions/generateVoiceResponse.js.map +1 -1
  23. package/dist/ai/models.d.ts +1 -1
  24. package/dist/ai/models.d.ts.map +1 -1
  25. package/dist/ai/models.js +46 -28
  26. package/dist/ai/models.js.map +1 -1
  27. package/dist/ai/utils.d.ts.map +1 -1
  28. package/dist/ai/utils.js.map +1 -1
  29. package/dist/canvas/ApexPainter.d.ts +10 -10
  30. package/dist/canvas/ApexPainter.d.ts.map +1 -1
  31. package/dist/canvas/ApexPainter.js +21 -26
  32. package/dist/canvas/ApexPainter.js.map +1 -1
  33. package/dist/canvas/utils/bg.d.ts +1 -2
  34. package/dist/canvas/utils/bg.d.ts.map +1 -1
  35. package/dist/canvas/utils/bg.js +2 -5
  36. package/dist/canvas/utils/bg.js.map +1 -1
  37. package/dist/canvas/utils/charts.js +26 -26
  38. package/dist/canvas/utils/charts.js.map +1 -1
  39. package/dist/canvas/utils/general functions.d.ts +7 -7
  40. package/dist/canvas/utils/general functions.d.ts.map +1 -1
  41. package/dist/canvas/utils/general functions.js +47 -52
  42. package/dist/canvas/utils/general functions.js.map +1 -1
  43. package/dist/canvas/utils/types.d.ts +1 -3
  44. package/dist/canvas/utils/types.d.ts.map +1 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +45 -1
  47. package/dist/index.js.map +1 -1
  48. package/lib/ai/ApexAI.ts +550 -0
  49. package/lib/ai/buttons/drawMenu.ts +361 -0
  50. package/lib/ai/buttons/tools.ts +550 -0
  51. package/lib/ai/functions/chunkString.ts +3 -0
  52. package/lib/ai/functions/draw.ts +440 -0
  53. package/lib/ai/functions/generateVoiceResponse.ts +177 -0
  54. package/lib/ai/functions/imageReader.ts +24 -0
  55. package/lib/ai/functions/readFiles.ts +34 -0
  56. package/lib/ai/functions/readImagess.ts +41 -0
  57. package/lib/ai/functions/shouldDrawImage.ts +7 -0
  58. package/lib/ai/functions/typeWriter.ts +24 -0
  59. package/lib/ai/models.ts +589 -0
  60. package/lib/ai/utils.ts +23 -0
  61. package/lib/canvas/ApexPainter.ts +572 -0
  62. package/lib/canvas/utils/bg.ts +79 -0
  63. package/lib/canvas/utils/charts.ts +524 -0
  64. package/lib/canvas/utils/circular.ts +17 -0
  65. package/lib/canvas/utils/customLines.ts +49 -0
  66. package/lib/canvas/utils/general functions.ts +434 -0
  67. package/lib/canvas/utils/imageProperties.ts +403 -0
  68. package/lib/canvas/utils/radius.ts +26 -0
  69. package/lib/canvas/utils/textProperties.ts +68 -0
  70. package/lib/canvas/utils/types.ts +417 -0
  71. package/lib/canvas/utils/utils.ts +59 -0
  72. package/lib/index.ts +38 -0
  73. package/lib/utils.ts +8 -0
  74. package/package.json +15 -2
  75. package/tsconfig.json +21 -0
@@ -0,0 +1,403 @@
1
+ import { ImageProperties } from "./utils";
2
+
3
+ /**
4
+ * Applies shadow to the canvas context.
5
+ * @param ctx The canvas rendering context.
6
+ * @param shadow The shadow properties.
7
+ * @param x The x-coordinate of the shape.
8
+ * @param y The y-coordinate of the shape.
9
+ * @param width The width of the shape.
10
+ * @param height The height of the shape.
11
+ */
12
+ export function applyShadow(ctx: any, shadow: ImageProperties['shadow'], x: number, y: number, width: number, height: number): void {
13
+
14
+ ctx.save();
15
+
16
+ if (
17
+ shadow
18
+ ) {
19
+ ctx.globalAlpha = shadow.opacity || null;
20
+ ctx.filter = `blur(${shadow.blur || null}px)`;
21
+
22
+ const shadowX =
23
+ x + (shadow.offsetX || 0);
24
+ const shadowY =
25
+ y + (shadow.offsetY || 0);
26
+
27
+ objectRadius(ctx, shadowX, shadowY, width, height, shadow.borderRadius || 2)
28
+
29
+ ctx.fillStyle = shadow.color || "transparent";
30
+ ctx.fill();
31
+ }
32
+
33
+ ctx.filter = "none";
34
+ ctx.globalAlpha = 1;
35
+ ctx.restore();
36
+
37
+ }
38
+
39
+
40
+
41
+ /**
42
+ * Applies stroke to the canvas context.
43
+ * @param ctx The canvas rendering context.
44
+ * @param stroke The stroke properties.
45
+ * @param x The x-coordinate of the shape.
46
+ * @param y The y-coordinate of the shape.
47
+ * @param width The width of the shape.
48
+ * @param height The height of the shape.
49
+ */
50
+ export function applyStroke(ctx: any, stroke: ImageProperties['stroke'], x: number, y: number, width: number, height: number, gradient?: any): void {
51
+ ctx.save();
52
+
53
+ if (stroke) {
54
+ if (gradient) {
55
+ const gradientFill = createGradient(
56
+ ctx,
57
+ gradient,
58
+ x,
59
+ y,
60
+ x + width,
61
+ y + height,
62
+ );
63
+ ctx.strokeStyle = gradientFill;
64
+ } else {
65
+ ctx.strokeStyle = stroke.color || "transparent";
66
+ }
67
+ ctx.lineWidth = stroke.width || 0;
68
+
69
+ const adjustedX = x - (stroke.position || 0);
70
+ const adjustedY = y - (stroke.position || 0);
71
+ const adjustedWidth = width + (stroke.position || 0) * 2;
72
+ const adjustedHeight = height + (stroke.position || 0) * 2;
73
+
74
+ objectRadius(ctx, adjustedX, adjustedY, adjustedWidth, adjustedHeight, stroke.borderRadius || 2);
75
+
76
+ ctx.stroke();
77
+ }
78
+
79
+ ctx.restore();
80
+ }
81
+
82
+ /**
83
+ * Draws a shape on the canvas context.
84
+ * @param ctx The canvas rendering context.
85
+ * @param shapeSettings The settings for the shape.
86
+ */
87
+ export function drawShape(ctx: any, shapeSettings: any) {
88
+ const { source, x, y, width, height, rotation, borderRadius, stroke, shadow, isFilled, color, gradient } = shapeSettings;
89
+
90
+ const shapeName = source.toLowerCase();
91
+
92
+ switch (shapeName) {
93
+ case 'circle':
94
+ ctx.save();
95
+ applyShadow(ctx, shadow, x, y, width, height);
96
+ applyRotation(ctx, rotation, x, y, width, height);
97
+ ctx.beginPath();
98
+ ctx.arc(x + width / 2, y + height / 2, width / 2, 0, Math.PI * 2);
99
+ break;
100
+ case 'square':
101
+ ctx.save();
102
+ applyRotation(ctx, rotation, x, y, width, height);
103
+ applyShadow(ctx, shadow, x, y, width, height);
104
+ break;
105
+ case 'triangle':
106
+ ctx.save();
107
+ applyRotation(ctx, rotation, x, y, width, height);
108
+ applyShadow(ctx, shadow, x, y, width, height);
109
+ ctx.beginPath();
110
+ ctx.moveTo(x, y + height);
111
+ ctx.lineTo(x + width / 2, y);
112
+ ctx.lineTo(x + width, y + height);
113
+ ctx.closePath();
114
+ break;
115
+ case 'pentagon':
116
+ ctx.save();
117
+ applyRotation(ctx, rotation, x, y, width, height);
118
+ applyShadow(ctx, shadow, x, y, width, height);
119
+ ctx.beginPath();
120
+ for (let i = 0; i < 5; i++) {
121
+ ctx.lineTo(x + width / 2 + width / 2 * Math.sin(i * 2 * Math.PI / 5),
122
+ y + height / 2 - height / 2 * Math.cos(i * 2 * Math.PI / 5));
123
+ }
124
+ ctx.closePath();
125
+ break;
126
+ case 'hexagon':
127
+ ctx.save();
128
+ applyRotation(ctx, rotation, x, y, width, height);
129
+ applyShadow(ctx, shadow, x, y, width, height);
130
+ ctx.beginPath();
131
+ for (let i = 0; i < 6; i++) {
132
+ ctx.lineTo(x + width / 2 + width / 2 * Math.sin(i * 2 * Math.PI / 6),
133
+ y + height / 2 - height / 2 * Math.cos(i * 2 * Math.PI / 6));
134
+ }
135
+ ctx.closePath();
136
+ break;
137
+ case 'heptagon':
138
+ ctx.save();
139
+ applyRotation(ctx, rotation, x, y, width, height);
140
+ applyShadow(ctx, shadow, x, y, width, height);
141
+ ctx.beginPath();
142
+ for (let i = 0; i < 7; i++) {
143
+ ctx.lineTo(x + width / 2 + width / 2 * Math.sin(i * 2 * Math.PI / 7),
144
+ y + height / 2 - height / 2 * Math.cos(i * 2 * Math.PI / 7));
145
+ }
146
+ ctx.closePath();
147
+ break;
148
+ case 'octagon':
149
+ ctx.save();
150
+ applyRotation(ctx, rotation, x, y, width, height);
151
+ applyShadow(ctx, shadow, x, y, width, height);
152
+ ctx.beginPath();
153
+ for (let i = 0; i < 8; i++) {
154
+ ctx.lineTo(x + width / 2 + width / 2 * Math.sin(i * 2 * Math.PI / 8),
155
+ y + height / 2 - height / 2 * Math.cos(i * 2 * Math.PI / 8));
156
+ }
157
+ ctx.closePath();
158
+ case 'star':
159
+ ctx.save();
160
+ applyRotation(ctx, rotation, x, y, width, height);
161
+ applyShadow(ctx, shadow, x, y, width, height);
162
+ ctx.beginPath();
163
+ const numPoints = 5;
164
+ const outerRadius = Math.min(width, height) / 2;
165
+ const innerRadius = outerRadius / 2;
166
+ for (let i = 0; i < numPoints * 2; i++) {
167
+ const radius = i % 2 === 0 ? outerRadius : innerRadius;
168
+ const angle = Math.PI / numPoints * i;
169
+ ctx.lineTo(x + width / 2 + radius * Math.sin(angle),
170
+ y + height / 2 - radius * Math.cos(angle));
171
+ }
172
+ ctx.closePath();
173
+ break;
174
+ case 'oval':
175
+ ctx.save();
176
+ applyRotation(ctx, rotation, x, y, width, height);
177
+ applyShadow(ctx, shadow, x, y, width, height);
178
+
179
+ ctx.beginPath();
180
+ ctx.ellipse(x + width / 2, y + height / 2, width / 2, height / 2, 0, 0, Math.PI * 2);
181
+ ctx.closePath();
182
+ if (isFilled) {
183
+ ctx.fillStyle = color;
184
+ ctx.fill();
185
+ } else {
186
+ applyStroke(ctx, stroke, x, y, width, height);
187
+ }
188
+ ctx.restore();
189
+ break;
190
+ default:
191
+ throw new Error(`Unsupported shape: ${shapeName}`);
192
+ }
193
+ if (isFilled) {
194
+ if (borderRadius) {
195
+ objectRadius(ctx, x, y, width, height, borderRadius);
196
+ if (gradient) {
197
+ const gradientFill = createGradient(
198
+ ctx,
199
+ gradient,
200
+ x,
201
+ y,
202
+ x + width,
203
+ y + height,
204
+ );
205
+ ctx.fillStyle = gradientFill;
206
+ } else {
207
+ ctx.fillStyle = color || "transparent";
208
+ }
209
+ ctx.fill();
210
+ } else {
211
+ if (gradient) {
212
+ const gradientFill = createGradient(
213
+ ctx,
214
+ gradient,
215
+ x,
216
+ y,
217
+ x + width,
218
+ y + height,
219
+ );
220
+ ctx.fillStyle = gradientFill;
221
+ } else {
222
+ ctx.fillStyle = color || "transparent";
223
+ }
224
+ if (shapeName === 'square') {
225
+ ctx.fillRect(x, y, width, height);
226
+ } else if (shapeName === 'circle') {
227
+ ctx.fill();
228
+ } else {
229
+ ctx.fill()
230
+ }
231
+ }
232
+ } else {
233
+ if (gradient) {
234
+ // Call createGradient with correct coordinates
235
+ const gradientFill = createGradient(
236
+ ctx,
237
+ gradient,
238
+ x, // startX
239
+ y, // startY
240
+ x + width, // endX
241
+ y + height, // endY
242
+ );
243
+ ctx.fillStyle = gradientFill;
244
+ }
245
+ applyStroke(ctx, stroke, x, y, width, height, gradient);
246
+ }
247
+
248
+ ctx.restore();
249
+ }
250
+
251
+ export function createGradient(ctx: any, gradientOptions: any, startX: number, startY: number, endX: number, endY: number) {
252
+ if (!gradientOptions || !gradientOptions.type) {
253
+ throw new Error(
254
+ "Invalid gradient options. Provide a valid object with a type property.",
255
+ );
256
+ }
257
+
258
+ if (gradientOptions.type === "linear") {
259
+ if (
260
+ typeof startX !== "number" ||
261
+ typeof startY !== "number" ||
262
+ typeof endX !== "number" ||
263
+ typeof endY !== "number"
264
+ ) {
265
+ throw new Error(
266
+ "Invalid gradient options for linear gradient. Numeric values are required for startX, startY, endX, and endY.",
267
+ );
268
+ }
269
+ } else if (gradientOptions.type === "radial") {
270
+ if (
271
+ typeof gradientOptions.startX !== "number" ||
272
+ typeof gradientOptions.startY !== "number" ||
273
+ typeof gradientOptions.startRadius !== "number" ||
274
+ typeof gradientOptions.endX !== "number" ||
275
+ typeof gradientOptions.endY !== "number" ||
276
+ typeof gradientOptions.endRadius !== "number"
277
+ ) {
278
+ throw new Error(
279
+ "Invalid gradient options for radial gradient. Numeric values are required for startX, startY, startRadius, endX, endY, and endRadius.",
280
+ );
281
+ }
282
+ } else {
283
+ throw new Error('Unsupported gradient type. Use "linear" or "radial".');
284
+ }
285
+
286
+ const gradient =
287
+ gradientOptions.type === "linear"
288
+ ? ctx.createLinearGradient(startX, startY, endX, endY)
289
+ : ctx.createRadialGradient(
290
+ gradientOptions.startX,
291
+ gradientOptions.startY,
292
+ gradientOptions.startRadius,
293
+ gradientOptions.endX,
294
+ gradientOptions.endY,
295
+ gradientOptions.endRadius,
296
+ );
297
+
298
+ for (const colorStop of gradientOptions.colors) {
299
+ gradient.addColorStop(colorStop.stop, colorStop.color);
300
+ }
301
+
302
+ return gradient;
303
+ }
304
+
305
+
306
+ /**
307
+ * Applies rotation to the canvas context.
308
+ * @param ctx The canvas rendering context.
309
+ * @param rotation The rotation angle in degrees.
310
+ * @param x The x-coordinate of the center of rotation.
311
+ * @param y The y-coordinate of the center of rotation.
312
+ * @param width The width of the shape.
313
+ * @param height The height of the shape.
314
+ */
315
+ export function applyRotation(ctx: any, rotation: number, x: number, y: number, width: number, height: number): void {
316
+ if (rotation !== undefined) {
317
+ const rotationX = x + width / 2;
318
+ const rotationY = y + height / 2;
319
+ ctx.translate(rotationX, rotationY);
320
+ ctx.rotate(rotation * Math.PI / 180);
321
+ ctx.translate(-rotationX, -rotationY);
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Applies border radius to the canvas context.
327
+ * @param ctx The canvas rendering context.
328
+ * @param image The image properties containing the border radius.
329
+ * @param x The x-coordinate of the shape.
330
+ * @param y The y-coordinate of the shape.
331
+ * @param width The width of the shape.
332
+ * @param height The height of the shape.
333
+ * @param borderRadius The border radius value.
334
+ */
335
+ export function imageRadius(ctx: any, image: any, x: number, y: number, width: number, height: number, borderRadius: any ): void {
336
+ ctx.save();
337
+ ctx.beginPath();
338
+
339
+ if (borderRadius === "circular") {
340
+ const circleRadius = Math.min(width, height) / 2;
341
+ ctx.arc(x + width / 2, y + height / 2, circleRadius, 0, 2 * Math.PI);
342
+ } else {
343
+ ctx.moveTo(x + borderRadius, y);
344
+ ctx.lineTo(x + width - borderRadius, y);
345
+ ctx.quadraticCurveTo(x + width, y, x + width, y + borderRadius);
346
+ ctx.lineTo(x + width, y + height - borderRadius);
347
+ ctx.quadraticCurveTo(
348
+ x + width,
349
+ y + height,
350
+ x + width - borderRadius,
351
+ y + height,
352
+ );
353
+ ctx.lineTo(x + borderRadius, y + height);
354
+ ctx.quadraticCurveTo(x, y + height, x, y + height - borderRadius);
355
+ ctx.lineTo(x, y + borderRadius);
356
+ ctx.quadraticCurveTo(x, y, x + borderRadius, y);
357
+ }
358
+
359
+ ctx.closePath();
360
+ ctx.clip();
361
+ ctx.drawImage(image, x, y, width, height);
362
+ ctx.restore();
363
+ }
364
+
365
+ /**
366
+ * Applies border radius to the canvas context for objects.
367
+ * @param ctx The canvas rendering context.
368
+ * @param x The x-coordinate of the object.
369
+ * @param y The y-coordinate of the object.
370
+ * @param width The width of the object.
371
+ * @param height The height of the object.
372
+ * @param borderRadius The border radius value.
373
+ */
374
+ export function objectRadius(ctx: any, x: any, y: any, width: number, height: number, borderRadius: any = 0.1): void {
375
+ ctx.save();
376
+ if (borderRadius === "circular") {
377
+ const circleRadius = Math.min(width, height) / 2;
378
+ ctx.beginPath();
379
+ ctx.arc(x + width / 2, y + height / 2, circleRadius, 0, 2 * Math.PI);
380
+ ctx.closePath();
381
+ } else if (borderRadius) {
382
+ ctx.beginPath();
383
+ ctx.moveTo(x + borderRadius, y);
384
+ ctx.lineTo(x + width - borderRadius, y);
385
+ ctx.quadraticCurveTo(x + width, y, x + width, y + borderRadius);
386
+ ctx.lineTo(x + width, y + height - borderRadius);
387
+ ctx.quadraticCurveTo(
388
+ x + width,
389
+ y + height,
390
+ x + width - borderRadius,
391
+ y + height,
392
+ );
393
+ ctx.lineTo(x + borderRadius, y + height);
394
+ ctx.quadraticCurveTo(x, y + height, x, y + height - borderRadius);
395
+ ctx.lineTo(x, y + borderRadius);
396
+ ctx.quadraticCurveTo(x, y, x + borderRadius, y);
397
+ ctx.closePath();
398
+ } else {
399
+ ctx.fillRect(x, y, width, height);
400
+ }
401
+ ctx.restore();
402
+ }
403
+
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Applies a radius border to the canvas context.
3
+ * @param ctx The canvas rendering context.
4
+ * @param width The width of the canvas.
5
+ * @param height The height of the canvas.
6
+ * @param radius The radius of the border.
7
+ * @returns A void.
8
+ */
9
+ export function radiusBorder(ctx: any, x: number = 0, y: number = 0, width: number, height: number, radius: number = 0): void {
10
+ const minDimension = Math.min(width, height);
11
+ const maxRadius = minDimension / 2;
12
+ const clipRadius = Math.min(radius, maxRadius);
13
+ ctx.save();
14
+ ctx.beginPath();
15
+ ctx.moveTo(x + clipRadius, y);
16
+ ctx.lineTo(x + width - clipRadius, y);
17
+ ctx.quadraticCurveTo(x + width, y, x + width, y + clipRadius);
18
+ ctx.lineTo(x + width, y + height - clipRadius);
19
+ ctx.quadraticCurveTo(x + width, y + height, x + width - clipRadius, y + height);
20
+ ctx.lineTo(x + clipRadius, y + height);
21
+ ctx.quadraticCurveTo(x, y + height, x, y + height - clipRadius);
22
+ ctx.lineTo(x, y + clipRadius);
23
+ ctx.quadraticCurveTo(x, y, x + clipRadius, y);
24
+ ctx.closePath();
25
+ ctx.clip();
26
+ }
@@ -0,0 +1,68 @@
1
+ import { TextObject } from "./types";
2
+
3
+ /**
4
+ * Draws text on the canvas context.
5
+ * @param ctx The canvas rendering context.
6
+ * @param textOptions The options for the text.
7
+ */
8
+ export function drawText(ctx: any, textOptions: TextObject) {
9
+ ctx.save();
10
+ ctx.font = `${textOptions.isBold ? 'bold ' : ''}${textOptions.fontSize || 16}px ${textOptions.fontName || "Arial"}`;
11
+ ctx.textAlign = textOptions.textAlign || 'left';
12
+ ctx.textBaseline = textOptions.textBaseline || 'alphabetic';
13
+
14
+ if (textOptions.shadow) {
15
+ const { color, offsetX, offsetY, blur } = textOptions.shadow;
16
+ ctx.shadowColor = color || "transparent";
17
+ ctx.shadowOffsetX = offsetX || 0;
18
+ ctx.shadowOffsetY = offsetY || 0;
19
+ ctx.shadowBlur = blur || 0;
20
+ }
21
+
22
+ ctx.fillStyle = textOptions.color || 'darkgray';
23
+
24
+ if (textOptions.maxWidth) {
25
+ WrappedText(ctx, textOptions.text || 'Hello World', textOptions.x || 0, textOptions.y || 0, textOptions.maxWidth, textOptions);
26
+ } else {
27
+ ctx.fillText(textOptions.text, textOptions.x, textOptions.y);
28
+ }
29
+
30
+ if (textOptions.stroke && textOptions.stroke.color && textOptions.stroke.width) {
31
+ ctx.strokeStyle = textOptions.stroke.color;
32
+ ctx.lineWidth = textOptions.stroke.width;
33
+ ctx.strokeText(textOptions.text, textOptions.x, textOptions.y);
34
+ }
35
+ ctx.restore();
36
+ }
37
+
38
+ /**
39
+ * Draws wrapped text on the canvas context.
40
+ * @param ctx The canvas rendering context.
41
+ * @param text The text to be drawn.
42
+ * @param x The x-coordinate of the starting point of the text.
43
+ * @param y The y-coordinate of the starting point of the text.
44
+ * @param maxWidth The maximum width for wrapping the text.
45
+ * @param textOptions The options for the text.
46
+ */
47
+ export function WrappedText(ctx: any, text: string, x: number, y: number, maxWidth: number, textOptions: TextObject) {
48
+ const words = text.split(' ');
49
+ let currentLine = '';
50
+ const fontSize = textOptions.fontSize || 16;
51
+ for (let n = 0; n < words.length; n++) {
52
+ const testLine = currentLine + words[n] + ' ';
53
+ const metrics = ctx.measureText(testLine);
54
+ const testWidth = metrics.width;
55
+
56
+ if (testWidth > maxWidth && n > 0) {
57
+ const adjustedY = y + (textOptions.lineHeight || fontSize) / 2;
58
+ ctx.fillText(currentLine.trim(), x, adjustedY);
59
+ currentLine = words[n] + ' ';
60
+ y += textOptions.lineHeight || fontSize;
61
+ } else {
62
+ currentLine = testLine;
63
+ }
64
+ }
65
+
66
+ const adjustedY = y + (textOptions.lineHeight || fontSize) / 2;
67
+ ctx.fillText(currentLine.trim(), x, adjustedY);
68
+ }