canvu-react 0.3.23 → 0.3.25

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.
package/dist/index.cjs CHANGED
@@ -85,6 +85,47 @@ var Camera2D = class {
85
85
  }
86
86
  };
87
87
 
88
+ // src/image/canvas-encode.ts
89
+ var DEFAULT_FALLBACK_MIME_TYPES = ["image/png"];
90
+ var tryCanvasToBlob = (canvas, mimeType, quality) => new Promise((resolve) => {
91
+ canvas.toBlob((blob) => resolve(blob), mimeType, quality);
92
+ });
93
+ var blobFromDataUrl = async (dataUrl) => {
94
+ const response = await fetch(dataUrl);
95
+ const blob = await response.blob();
96
+ if (blob.size === 0) {
97
+ throw new Error("Failed to encode canvas to blob");
98
+ }
99
+ return blob;
100
+ };
101
+ async function encodeCanvasToBlob(canvas, options) {
102
+ const primaryMimeType = options?.mimeType ?? "image/png";
103
+ const quality = options?.quality;
104
+ const mimeTypes = [
105
+ primaryMimeType,
106
+ ...options?.fallbackMimeTypes ?? DEFAULT_FALLBACK_MIME_TYPES
107
+ ].filter(
108
+ (mimeType, index, mimeTypeList) => mimeTypeList.indexOf(mimeType) === index
109
+ );
110
+ for (const mimeType of mimeTypes) {
111
+ const blob = await tryCanvasToBlob(
112
+ canvas,
113
+ mimeType,
114
+ mimeType === primaryMimeType ? quality : void 0
115
+ );
116
+ if (blob) {
117
+ return blob;
118
+ }
119
+ }
120
+ for (const mimeType of mimeTypes) {
121
+ const dataUrl = canvas.toDataURL(mimeType, quality);
122
+ if (dataUrl && dataUrl !== "data:,") {
123
+ return blobFromDataUrl(dataUrl);
124
+ }
125
+ }
126
+ throw new Error("Failed to encode canvas to blob");
127
+ }
128
+
88
129
  // src/image/indexed-db-image-store.ts
89
130
  var DB_NAME = "canvu-image-store";
90
131
  var DB_VERSION = 1;
@@ -200,21 +241,6 @@ async function renderPageToCanvas(page, scale) {
200
241
  await page.render({ canvas, viewport }).promise;
201
242
  return { canvas, width: w, height: h };
202
243
  }
203
- function canvasToBlob(canvas, mime, quality) {
204
- return new Promise((resolve, reject) => {
205
- canvas.toBlob(
206
- (blob) => {
207
- if (!blob) {
208
- reject(new Error("Could not encode blob"));
209
- return;
210
- }
211
- resolve(blob);
212
- },
213
- mime,
214
- quality
215
- );
216
- });
217
- }
218
244
  function normalizePdfPageNumbers(pageNumbers, pageCount) {
219
245
  if (!pageNumbers || pageNumbers.length === 0) {
220
246
  return Array.from({ length: pageCount }, (_, index) => index + 1);
@@ -276,7 +302,7 @@ async function loadPdfToStore(file, store, options) {
276
302
  const page = await pdf.getPage(pageNumber);
277
303
  const { canvas, width, height } = await renderPageToCanvas(page, scale);
278
304
  const mime = "image/png";
279
- const pageBlob = await canvasToBlob(canvas, mime);
305
+ const pageBlob = await encodeCanvasToBlob(canvas, { mimeType: mime });
280
306
  const blobId = await store.storeOriginal(pageBlob);
281
307
  const thumbnailBlobId = storeThumbnails ? await (async () => {
282
308
  const thumbScale = Math.min(1, 256 / Math.max(width, height));
@@ -291,7 +317,9 @@ async function loadPdfToStore(file, store, options) {
291
317
  tCtx.imageSmoothingQuality = "high";
292
318
  tCtx.drawImage(canvas, 0, 0, tw, th);
293
319
  }
294
- const thumbBlob = await canvasToBlob(thumbCanvas, mime);
320
+ const thumbBlob = await encodeCanvasToBlob(thumbCanvas, {
321
+ mimeType: mime
322
+ });
295
323
  return await store.storeThumbnail(thumbBlob);
296
324
  })() : "";
297
325
  const pageResult = {
@@ -331,19 +359,9 @@ function loadImageFromObjectUrl(objectUrl) {
331
359
  });
332
360
  }
333
361
  function canvasToObjectUrl(canvas, mime, quality) {
334
- return new Promise((resolve, reject) => {
335
- canvas.toBlob(
336
- (blob) => {
337
- if (!blob) {
338
- reject(new Error("Could not encode image blob"));
339
- return;
340
- }
341
- resolve(URL.createObjectURL(blob));
342
- },
343
- mime,
344
- quality
345
- );
346
- });
362
+ return encodeCanvasToBlob(canvas, { mimeType: mime, quality }).then(
363
+ (blob) => URL.createObjectURL(blob)
364
+ );
347
365
  }
348
366
  async function loadImageFileAsRasterSceneSource(file, maxDimensionOrOptions) {
349
367
  const { maxDimension: maxDim, embedMode } = normalizeLoadOptions(maxDimensionOrOptions);
@@ -561,16 +579,23 @@ function distanceBetween(a, b) {
561
579
  function midpoint(a, b) {
562
580
  return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
563
581
  }
564
- function wheelDeltaYPixels(e) {
565
- switch (e.deltaMode) {
582
+ function wheelDeltaPixels(delta, deltaMode) {
583
+ switch (deltaMode) {
566
584
  case WheelEvent.DOM_DELTA_LINE:
567
- return e.deltaY * 16;
585
+ return delta * 16;
568
586
  case WheelEvent.DOM_DELTA_PAGE:
569
- return e.deltaY * 400;
587
+ return delta * 400;
570
588
  default:
571
- return e.deltaY;
589
+ return delta;
572
590
  }
573
591
  }
592
+ var TRACKPAD_MAX_DELTA = 20;
593
+ var MOUSE_WHEEL_DAMPING = 0.4;
594
+ function softenWheelDelta(d) {
595
+ const a = Math.abs(d);
596
+ if (a <= TRACKPAD_MAX_DELTA) return d;
597
+ return Math.sign(d) * (TRACKPAD_MAX_DELTA + (a - TRACKPAD_MAX_DELTA) * MOUSE_WHEEL_DAMPING);
598
+ }
574
599
  function attachViewportInput(options) {
575
600
  const {
576
601
  element,
@@ -593,8 +618,8 @@ function attachViewportInput(options) {
593
618
  const onWheel = (e) => {
594
619
  if (e.ctrlKey || e.metaKey) {
595
620
  e.preventDefault();
596
- const dy = wheelDeltaYPixels(e);
597
- const normDy = Math.abs(dy) < 20 ? dy * 12 : dy;
621
+ const dy = wheelDeltaPixels(e.deltaY, e.deltaMode);
622
+ const normDy = Math.abs(dy) < TRACKPAD_MAX_DELTA ? dy * 12 : dy;
598
623
  const factor = Math.exp(-normDy * wheelZoomSensitivity);
599
624
  const rect = element.getBoundingClientRect();
600
625
  camera.setZoom(camera.zoom * factor, {
@@ -605,8 +630,10 @@ function attachViewportInput(options) {
605
630
  return;
606
631
  }
607
632
  e.preventDefault();
608
- camera.x -= e.deltaX * wheelPanSensitivity / camera.zoom;
609
- camera.y -= e.deltaY * wheelPanSensitivity / camera.zoom;
633
+ const panDx = softenWheelDelta(wheelDeltaPixels(e.deltaX, e.deltaMode));
634
+ const panDy = softenWheelDelta(wheelDeltaPixels(e.deltaY, e.deltaMode));
635
+ camera.x -= panDx * wheelPanSensitivity / camera.zoom;
636
+ camera.y -= panDy * wheelPanSensitivity / camera.zoom;
610
637
  onUpdate();
611
638
  };
612
639
  const onPointerDown = (e) => {
@@ -2404,6 +2431,7 @@ exports.createShapeId = createShapeId;
2404
2431
  exports.createTextItem = createTextItem;
2405
2432
  exports.cullItemsByViewport = cullItemsByViewport;
2406
2433
  exports.deleteManagedImage = deleteManagedImage;
2434
+ exports.encodeCanvasToBlob = encodeCanvasToBlob;
2407
2435
  exports.expandCustomShapeTemplate = expandCustomShapeTemplate;
2408
2436
  exports.formatCameraTransform = formatCameraTransform;
2409
2437
  exports.formatItemPlacementTransform = formatItemPlacementTransform;