@umituz/web-canvas 1.0.1 → 1.0.2

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.
@@ -7,6 +7,7 @@ import {
7
7
  var CanvasRenderer = class {
8
8
  constructor(config = DEFAULT_CANVAS_CONFIG) {
9
9
  this.config = { ...DEFAULT_CANVAS_CONFIG, ...config };
10
+ this.imageCache = /* @__PURE__ */ new Map();
10
11
  }
11
12
  /**
12
13
  * Create a new canvas element
@@ -108,17 +109,37 @@ var CanvasRenderer = class {
108
109
  }
109
110
  }
110
111
  /**
111
- * Load image from URL
112
+ * Load image from URL with caching
112
113
  */
113
114
  loadImage(url) {
115
+ if (this.imageCache.has(url)) {
116
+ return Promise.resolve(this.imageCache.get(url));
117
+ }
114
118
  return new Promise((resolve, reject) => {
115
119
  const img = new Image();
116
- img.crossOrigin = this.config.useCORS ? "anonymous" : void 0;
117
- img.onload = () => resolve(img);
120
+ if (this.config.useCORS) {
121
+ img.crossOrigin = "anonymous";
122
+ }
123
+ img.onload = () => {
124
+ this.imageCache.set(url, img);
125
+ resolve(img);
126
+ };
118
127
  img.onerror = () => reject(new Error(`Failed to load image: ${url}`));
119
128
  img.src = url;
120
129
  });
121
130
  }
131
+ /**
132
+ * Clear image cache to free memory
133
+ */
134
+ clearImageCache() {
135
+ this.imageCache.clear();
136
+ }
137
+ /**
138
+ * Get cache size for monitoring
139
+ */
140
+ getCacheSize() {
141
+ return this.imageCache.size;
142
+ }
122
143
  /**
123
144
  * Create gradient
124
145
  */
@@ -200,10 +221,15 @@ var CanvasRenderer = class {
200
221
 
201
222
  // src/infrastructure/renderers/PatternRenderer.ts
202
223
  var PatternRenderer = class {
224
+ constructor() {
225
+ this.patternCanvasCache = /* @__PURE__ */ new Map();
226
+ this.MAX_CACHE_SIZE = 10;
227
+ }
203
228
  /**
204
229
  * Render pattern on canvas
205
230
  */
206
231
  renderPattern(ctx, pattern, dimensions, color = "#000000") {
232
+ if (pattern === "none") return;
207
233
  ctx.save();
208
234
  ctx.globalAlpha = 0.1;
209
235
  switch (pattern) {
@@ -222,62 +248,65 @@ var PatternRenderer = class {
222
248
  case "checkers":
223
249
  this.renderCheckerPattern(ctx, dimensions, color);
224
250
  break;
225
- case "none":
226
- default:
227
- break;
228
251
  }
229
252
  ctx.restore();
230
253
  }
231
254
  /**
232
- * Render dot pattern
255
+ * Clear pattern cache to free memory
256
+ */
257
+ clearCache() {
258
+ this.patternCanvasCache.clear();
259
+ }
260
+ /**
261
+ * Render dot pattern - optimized with batch rendering
233
262
  */
234
263
  renderDotPattern(ctx, dimensions, color) {
235
264
  ctx.fillStyle = color;
236
265
  const spacing = 30;
266
+ const radius = 2;
267
+ ctx.beginPath();
237
268
  for (let x = spacing; x < dimensions.width; x += spacing) {
238
269
  for (let y = spacing; y < dimensions.height; y += spacing) {
239
- ctx.beginPath();
240
- ctx.arc(x, y, 2, 0, Math.PI * 2);
241
- ctx.fill();
270
+ ctx.moveTo(x + radius, y);
271
+ ctx.arc(x, y, radius, 0, Math.PI * 2);
242
272
  }
243
273
  }
274
+ ctx.fill();
244
275
  }
245
276
  /**
246
- * Render grid pattern
277
+ * Render grid pattern - optimized with single path
247
278
  */
248
279
  renderGridPattern(ctx, dimensions, color) {
249
280
  ctx.strokeStyle = color;
250
281
  ctx.lineWidth = 1;
251
282
  const spacing = 30;
283
+ ctx.beginPath();
252
284
  for (let x = 0; x <= dimensions.width; x += spacing) {
253
- ctx.beginPath();
254
285
  ctx.moveTo(x, 0);
255
286
  ctx.lineTo(x, dimensions.height);
256
- ctx.stroke();
257
287
  }
258
288
  for (let y = 0; y <= dimensions.height; y += spacing) {
259
- ctx.beginPath();
260
289
  ctx.moveTo(0, y);
261
290
  ctx.lineTo(dimensions.width, y);
262
- ctx.stroke();
263
291
  }
292
+ ctx.stroke();
264
293
  }
265
294
  /**
266
- * Render line pattern
295
+ * Render line pattern - optimized with single path
267
296
  */
268
297
  renderLinePattern(ctx, dimensions, color) {
269
298
  ctx.strokeStyle = color;
270
299
  ctx.lineWidth = 2;
271
300
  const spacing = 20;
301
+ ctx.beginPath();
272
302
  for (let y = spacing; y < dimensions.height; y += spacing) {
273
- ctx.beginPath();
274
303
  ctx.moveTo(0, y);
275
304
  ctx.lineTo(dimensions.width, y);
276
- ctx.stroke();
277
305
  }
306
+ ctx.stroke();
278
307
  }
279
308
  /**
280
- * Render wave pattern
309
+ * Render wave pattern - optimized with pre-calculated values
281
310
  */
282
311
  renderWavePattern(ctx, dimensions, color) {
283
312
  ctx.strokeStyle = color;
@@ -285,15 +314,15 @@ var PatternRenderer = class {
285
314
  const amplitude = 10;
286
315
  const frequency = 0.1;
287
316
  const spacing = 40;
317
+ const step = 5;
288
318
  for (let y = spacing; y < dimensions.height; y += spacing) {
289
319
  ctx.beginPath();
290
- for (let x = 0; x <= dimensions.width; x += 5) {
320
+ const startX = 0;
321
+ const startY = y + Math.sin(startX * frequency) * amplitude;
322
+ ctx.moveTo(startX, startY);
323
+ for (let x = step; x <= dimensions.width; x += step) {
291
324
  const waveY = y + Math.sin(x * frequency) * amplitude;
292
- if (x === 0) {
293
- ctx.moveTo(x, waveY);
294
- } else {
295
- ctx.lineTo(x, waveY);
296
- }
325
+ ctx.lineTo(x, waveY);
297
326
  }
298
327
  ctx.stroke();
299
328
  }
@@ -316,6 +345,9 @@ var PatternRenderer = class {
316
345
  // src/infrastructure/services/DeviceConfigService.ts
317
346
  var DeviceConfigService = class _DeviceConfigService {
318
347
  constructor() {
348
+ this.phonesCache = null;
349
+ this.tabletsCache = null;
350
+ this.allDevicesCache = null;
319
351
  this.devices = /* @__PURE__ */ new Map();
320
352
  this.initializeDevices();
321
353
  }
@@ -412,13 +444,22 @@ var DeviceConfigService = class _DeviceConfigService {
412
444
  return this.devices.get(deviceType);
413
445
  }
414
446
  getAllDevices() {
415
- return Array.from(this.devices.values());
447
+ if (!this.allDevicesCache) {
448
+ this.allDevicesCache = Array.from(this.devices.values());
449
+ }
450
+ return this.allDevicesCache;
416
451
  }
417
452
  getPhones() {
418
- return this.getAllDevices().filter((d) => d.isPhone);
453
+ if (!this.phonesCache) {
454
+ this.phonesCache = this.getAllDevices().filter((d) => d.isPhone);
455
+ }
456
+ return this.phonesCache;
419
457
  }
420
458
  getTablets() {
421
- return this.getAllDevices().filter((d) => d.isTablet);
459
+ if (!this.tabletsCache) {
460
+ this.tabletsCache = this.getAllDevices().filter((d) => d.isTablet);
461
+ }
462
+ return this.tabletsCache;
422
463
  }
423
464
  isPhone(deviceType) {
424
465
  const config = this.getDeviceConfig(deviceType);
@@ -437,10 +478,20 @@ var DeviceConfigService = class _DeviceConfigService {
437
478
  // src/infrastructure/renderers/ScreenshotRenderer.ts
438
479
  var ScreenshotRenderer = class {
439
480
  constructor() {
481
+ this.renderCache = /* @__PURE__ */ new Map();
482
+ this.MAX_CACHE_SIZE = 5;
440
483
  this.canvasRenderer = new CanvasRenderer();
441
484
  this.patternRenderer = new PatternRenderer();
442
485
  this.deviceConfigService = DeviceConfigService.getInstance();
443
486
  }
487
+ /**
488
+ * Clear render cache to free memory
489
+ */
490
+ clearCache() {
491
+ this.renderCache.clear();
492
+ this.canvasRenderer.clearImageCache?.();
493
+ this.patternRenderer.clearCache?.();
494
+ }
444
495
  /**
445
496
  * Render device frame
446
497
  */
@@ -492,7 +543,7 @@ var ScreenshotRenderer = class {
492
543
  ctx.fill();
493
544
  }
494
545
  /**
495
- * Render background
546
+ * Render background - optimized
496
547
  */
497
548
  renderBackground(ctx, design, dimensions) {
498
549
  if (design.backgroundGradientEnd) {