canvu-react 0.3.24 → 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 +49 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +49 -31
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +105 -30
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +105 -30
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/react.cjs
CHANGED
|
@@ -718,6 +718,47 @@ var init_shape_builders = __esm({
|
|
|
718
718
|
}
|
|
719
719
|
});
|
|
720
720
|
|
|
721
|
+
// src/image/canvas-encode.ts
|
|
722
|
+
var DEFAULT_FALLBACK_MIME_TYPES = ["image/png"];
|
|
723
|
+
var tryCanvasToBlob = (canvas, mimeType, quality) => new Promise((resolve) => {
|
|
724
|
+
canvas.toBlob((blob) => resolve(blob), mimeType, quality);
|
|
725
|
+
});
|
|
726
|
+
var blobFromDataUrl = async (dataUrl) => {
|
|
727
|
+
const response = await fetch(dataUrl);
|
|
728
|
+
const blob = await response.blob();
|
|
729
|
+
if (blob.size === 0) {
|
|
730
|
+
throw new Error("Failed to encode canvas to blob");
|
|
731
|
+
}
|
|
732
|
+
return blob;
|
|
733
|
+
};
|
|
734
|
+
async function encodeCanvasToBlob(canvas, options) {
|
|
735
|
+
const primaryMimeType = options?.mimeType ?? "image/png";
|
|
736
|
+
const quality = options?.quality;
|
|
737
|
+
const mimeTypes = [
|
|
738
|
+
primaryMimeType,
|
|
739
|
+
...options?.fallbackMimeTypes ?? DEFAULT_FALLBACK_MIME_TYPES
|
|
740
|
+
].filter(
|
|
741
|
+
(mimeType, index, mimeTypeList) => mimeTypeList.indexOf(mimeType) === index
|
|
742
|
+
);
|
|
743
|
+
for (const mimeType of mimeTypes) {
|
|
744
|
+
const blob = await tryCanvasToBlob(
|
|
745
|
+
canvas,
|
|
746
|
+
mimeType,
|
|
747
|
+
mimeType === primaryMimeType ? quality : void 0
|
|
748
|
+
);
|
|
749
|
+
if (blob) {
|
|
750
|
+
return blob;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
for (const mimeType of mimeTypes) {
|
|
754
|
+
const dataUrl = canvas.toDataURL(mimeType, quality);
|
|
755
|
+
if (dataUrl && dataUrl !== "data:,") {
|
|
756
|
+
return blobFromDataUrl(dataUrl);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
throw new Error("Failed to encode canvas to blob");
|
|
760
|
+
}
|
|
761
|
+
|
|
721
762
|
// src/image/indexed-db-image-store.ts
|
|
722
763
|
var DB_NAME = "canvu-image-store";
|
|
723
764
|
var DB_VERSION = 1;
|
|
@@ -836,19 +877,7 @@ function decodeImageToCanvas(blob, maxDimension) {
|
|
|
836
877
|
});
|
|
837
878
|
}
|
|
838
879
|
function canvasToBlob(canvas, mime, quality) {
|
|
839
|
-
return
|
|
840
|
-
canvas.toBlob(
|
|
841
|
-
(blob) => {
|
|
842
|
-
if (!blob) {
|
|
843
|
-
reject(new Error("Could not encode blob"));
|
|
844
|
-
return;
|
|
845
|
-
}
|
|
846
|
-
resolve(blob);
|
|
847
|
-
},
|
|
848
|
-
mime,
|
|
849
|
-
quality
|
|
850
|
-
);
|
|
851
|
-
});
|
|
880
|
+
return encodeCanvasToBlob(canvas, { mimeType: mime, quality });
|
|
852
881
|
}
|
|
853
882
|
async function loadImageToStore(file, store) {
|
|
854
883
|
const originalBlob = file;
|
|
@@ -916,21 +945,6 @@ async function renderPageToCanvas(page, scale) {
|
|
|
916
945
|
await page.render({ canvas, viewport }).promise;
|
|
917
946
|
return { canvas, width: w, height: h };
|
|
918
947
|
}
|
|
919
|
-
function canvasToBlob2(canvas, mime, quality) {
|
|
920
|
-
return new Promise((resolve, reject) => {
|
|
921
|
-
canvas.toBlob(
|
|
922
|
-
(blob) => {
|
|
923
|
-
if (!blob) {
|
|
924
|
-
reject(new Error("Could not encode blob"));
|
|
925
|
-
return;
|
|
926
|
-
}
|
|
927
|
-
resolve(blob);
|
|
928
|
-
},
|
|
929
|
-
mime,
|
|
930
|
-
quality
|
|
931
|
-
);
|
|
932
|
-
});
|
|
933
|
-
}
|
|
934
948
|
function normalizePdfPageNumbers(pageNumbers, pageCount) {
|
|
935
949
|
if (!pageNumbers || pageNumbers.length === 0) {
|
|
936
950
|
return Array.from({ length: pageCount }, (_, index) => index + 1);
|
|
@@ -992,7 +1006,7 @@ async function loadPdfToStore(file, store, options) {
|
|
|
992
1006
|
const page = await pdf.getPage(pageNumber);
|
|
993
1007
|
const { canvas, width, height } = await renderPageToCanvas(page, scale);
|
|
994
1008
|
const mime = "image/png";
|
|
995
|
-
const pageBlob = await
|
|
1009
|
+
const pageBlob = await encodeCanvasToBlob(canvas, { mimeType: mime });
|
|
996
1010
|
const blobId = await store.storeOriginal(pageBlob);
|
|
997
1011
|
const thumbnailBlobId = storeThumbnails ? await (async () => {
|
|
998
1012
|
const thumbScale = Math.min(1, 256 / Math.max(width, height));
|
|
@@ -1007,7 +1021,9 @@ async function loadPdfToStore(file, store, options) {
|
|
|
1007
1021
|
tCtx.imageSmoothingQuality = "high";
|
|
1008
1022
|
tCtx.drawImage(canvas, 0, 0, tw, th);
|
|
1009
1023
|
}
|
|
1010
|
-
const thumbBlob = await
|
|
1024
|
+
const thumbBlob = await encodeCanvasToBlob(thumbCanvas, {
|
|
1025
|
+
mimeType: mime
|
|
1026
|
+
});
|
|
1011
1027
|
return await store.storeThumbnail(thumbBlob);
|
|
1012
1028
|
})() : "";
|
|
1013
1029
|
const pageResult = {
|
|
@@ -7405,6 +7421,40 @@ var VectorViewport = react.forwardRef(
|
|
|
7405
7421
|
onWorldPointerLeaveRef.current = onWorldPointerLeave;
|
|
7406
7422
|
const onPlacementPreviewChangeRef = react.useRef(onPlacementPreviewChange);
|
|
7407
7423
|
onPlacementPreviewChangeRef.current = onPlacementPreviewChange;
|
|
7424
|
+
const directRemoteStrokePreviewRef = react.useRef(false);
|
|
7425
|
+
const remoteStrokePreviewFrameRef = react.useRef(null);
|
|
7426
|
+
const pendingRemoteStrokePreviewRef = react.useRef(null);
|
|
7427
|
+
const flushRemoteStrokePreview = react.useCallback(() => {
|
|
7428
|
+
remoteStrokePreviewFrameRef.current = null;
|
|
7429
|
+
const pending = pendingRemoteStrokePreviewRef.current;
|
|
7430
|
+
if (!pending) return;
|
|
7431
|
+
onPlacementPreviewChangeRef.current?.({
|
|
7432
|
+
kind: "stroke",
|
|
7433
|
+
tool: pending.tool,
|
|
7434
|
+
points: pending.points
|
|
7435
|
+
});
|
|
7436
|
+
}, []);
|
|
7437
|
+
const emitRemoteStrokePreview = react.useCallback(
|
|
7438
|
+
(tool, points) => {
|
|
7439
|
+
if (tool === "laser") return;
|
|
7440
|
+
directRemoteStrokePreviewRef.current = true;
|
|
7441
|
+
pendingRemoteStrokePreviewRef.current = { tool, points };
|
|
7442
|
+
if (remoteStrokePreviewFrameRef.current != null) return;
|
|
7443
|
+
remoteStrokePreviewFrameRef.current = requestAnimationFrame(
|
|
7444
|
+
flushRemoteStrokePreview
|
|
7445
|
+
);
|
|
7446
|
+
},
|
|
7447
|
+
[flushRemoteStrokePreview]
|
|
7448
|
+
);
|
|
7449
|
+
const emitRemoteStrokePreviewClear = react.useCallback(() => {
|
|
7450
|
+
if (remoteStrokePreviewFrameRef.current != null) {
|
|
7451
|
+
cancelAnimationFrame(remoteStrokePreviewFrameRef.current);
|
|
7452
|
+
remoteStrokePreviewFrameRef.current = null;
|
|
7453
|
+
}
|
|
7454
|
+
pendingRemoteStrokePreviewRef.current = null;
|
|
7455
|
+
directRemoteStrokePreviewRef.current = false;
|
|
7456
|
+
onPlacementPreviewChangeRef.current?.(null);
|
|
7457
|
+
}, []);
|
|
7408
7458
|
const overlayCameraTickRef = react.useRef(false);
|
|
7409
7459
|
overlayCameraTickRef.current = interactive || remotePresence != null && remotePresence.length > 0 || presenceOverlay != null;
|
|
7410
7460
|
const pruneEraserTrail = react.useCallback(
|
|
@@ -7523,6 +7573,7 @@ var VectorViewport = react.forwardRef(
|
|
|
7523
7573
|
if (itemId) {
|
|
7524
7574
|
renderSceneWithLivePenStroke(null);
|
|
7525
7575
|
}
|
|
7576
|
+
emitRemoteStrokePreviewClear();
|
|
7526
7577
|
setPlacementPreview(null);
|
|
7527
7578
|
commitCompletedStroke({
|
|
7528
7579
|
tool,
|
|
@@ -7534,6 +7585,7 @@ var VectorViewport = react.forwardRef(
|
|
|
7534
7585
|
},
|
|
7535
7586
|
[
|
|
7536
7587
|
commitCompletedStroke,
|
|
7588
|
+
emitRemoteStrokePreviewClear,
|
|
7537
7589
|
releaseInteractionPointer,
|
|
7538
7590
|
renderSceneWithLivePenStroke
|
|
7539
7591
|
]
|
|
@@ -7645,8 +7697,18 @@ var VectorViewport = react.forwardRef(
|
|
|
7645
7697
|
};
|
|
7646
7698
|
}, [onWorldPointerMove]);
|
|
7647
7699
|
react.useEffect(() => {
|
|
7700
|
+
if (directRemoteStrokePreviewRef.current && placementPreview === null) {
|
|
7701
|
+
return;
|
|
7702
|
+
}
|
|
7648
7703
|
onPlacementPreviewChangeRef.current?.(placementPreview);
|
|
7649
7704
|
}, [placementPreview]);
|
|
7705
|
+
react.useEffect(() => {
|
|
7706
|
+
return () => {
|
|
7707
|
+
if (remoteStrokePreviewFrameRef.current != null) {
|
|
7708
|
+
cancelAnimationFrame(remoteStrokePreviewFrameRef.current);
|
|
7709
|
+
}
|
|
7710
|
+
};
|
|
7711
|
+
}, []);
|
|
7650
7712
|
react.useEffect(() => {
|
|
7651
7713
|
const scene = sceneRef.current;
|
|
7652
7714
|
if (scene) {
|
|
@@ -8640,6 +8702,7 @@ var VectorViewport = react.forwardRef(
|
|
|
8640
8702
|
setPlacementPreview(null);
|
|
8641
8703
|
} else if (directPenStroke) {
|
|
8642
8704
|
setPlacementPreview(null);
|
|
8705
|
+
emitRemoteStrokePreview(tool, [startPoint]);
|
|
8643
8706
|
} else {
|
|
8644
8707
|
setPlacementPreview({
|
|
8645
8708
|
kind: "stroke",
|
|
@@ -8681,6 +8744,7 @@ var VectorViewport = react.forwardRef(
|
|
|
8681
8744
|
[
|
|
8682
8745
|
applePencilNav,
|
|
8683
8746
|
captureInteractionPointer,
|
|
8747
|
+
emitRemoteStrokePreview,
|
|
8684
8748
|
finalizeStrokeDragState,
|
|
8685
8749
|
renderSceneWithLivePenStroke,
|
|
8686
8750
|
screenToWorld
|
|
@@ -8739,6 +8803,7 @@ var VectorViewport = react.forwardRef(
|
|
|
8739
8803
|
activeInteractionPointerIdRef.current = e.pointerId;
|
|
8740
8804
|
activeInteractionPointerTargetRef.current = null;
|
|
8741
8805
|
setPlacementPreview(null);
|
|
8806
|
+
emitRemoteStrokePreview(tool, [startPoint]);
|
|
8742
8807
|
debugApplePencilPointer("native-pointerdown", {
|
|
8743
8808
|
pointerType: e.pointerType,
|
|
8744
8809
|
pointerId: e.pointerId,
|
|
@@ -8756,6 +8821,7 @@ var VectorViewport = react.forwardRef(
|
|
|
8756
8821
|
};
|
|
8757
8822
|
}, [
|
|
8758
8823
|
applePencilNav,
|
|
8824
|
+
emitRemoteStrokePreview,
|
|
8759
8825
|
finalizeStrokeDragState,
|
|
8760
8826
|
interactive,
|
|
8761
8827
|
renderSceneWithLivePenStroke,
|
|
@@ -8839,6 +8905,7 @@ var VectorViewport = react.forwardRef(
|
|
|
8839
8905
|
activeInteractionPointerTargetRef.current = null;
|
|
8840
8906
|
activeInteractionTouchIdRef.current = touch.identifier;
|
|
8841
8907
|
setPlacementPreview(null);
|
|
8908
|
+
emitRemoteStrokePreview(tool, [startPoint]);
|
|
8842
8909
|
debugApplePencilPointer("touchstart-stroke", {
|
|
8843
8910
|
touchId: touch.identifier,
|
|
8844
8911
|
touchType: touchKind(touch),
|
|
@@ -8870,6 +8937,7 @@ var VectorViewport = react.forwardRef(
|
|
|
8870
8937
|
renderSceneWithLivePenStroke(item);
|
|
8871
8938
|
}
|
|
8872
8939
|
setPlacementPreview(null);
|
|
8940
|
+
emitRemoteStrokePreview(st.tool, interpolated);
|
|
8873
8941
|
}
|
|
8874
8942
|
debugApplePencilPointer("touchmove-stroke", {
|
|
8875
8943
|
touchId: touch.identifier,
|
|
@@ -8932,6 +9000,7 @@ var VectorViewport = react.forwardRef(
|
|
|
8932
9000
|
};
|
|
8933
9001
|
}, [
|
|
8934
9002
|
applePencilNav,
|
|
9003
|
+
emitRemoteStrokePreview,
|
|
8935
9004
|
finalizeStrokeDragState,
|
|
8936
9005
|
interactive,
|
|
8937
9006
|
renderSceneWithLivePenStroke,
|
|
@@ -8986,6 +9055,7 @@ var VectorViewport = react.forwardRef(
|
|
|
8986
9055
|
renderSceneWithLivePenStroke(item);
|
|
8987
9056
|
}
|
|
8988
9057
|
setPlacementPreview(null);
|
|
9058
|
+
emitRemoteStrokePreview(st.tool, interpolated);
|
|
8989
9059
|
return;
|
|
8990
9060
|
}
|
|
8991
9061
|
if (st.tool === "laser") {
|
|
@@ -9127,6 +9197,9 @@ var VectorViewport = react.forwardRef(
|
|
|
9127
9197
|
}
|
|
9128
9198
|
const cam = cameraRef.current;
|
|
9129
9199
|
if (!cam) {
|
|
9200
|
+
if (st.kind === "stroke") {
|
|
9201
|
+
emitRemoteStrokePreviewClear();
|
|
9202
|
+
}
|
|
9130
9203
|
if (st.kind === "erase") {
|
|
9131
9204
|
eraserPreviewIdsRef.current.clear();
|
|
9132
9205
|
setEraserPreviewIds([]);
|
|
@@ -9358,6 +9431,8 @@ var VectorViewport = react.forwardRef(
|
|
|
9358
9431
|
document.removeEventListener("pointercancel", onUp);
|
|
9359
9432
|
};
|
|
9360
9433
|
}, [
|
|
9434
|
+
emitRemoteStrokePreview,
|
|
9435
|
+
emitRemoteStrokePreviewClear,
|
|
9361
9436
|
interactive,
|
|
9362
9437
|
pruneEraserTrail,
|
|
9363
9438
|
pruneLaserTrail,
|