@embedpdf/plugin-annotation 2.12.1 → 2.14.0
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 +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1912 -1456
- package/dist/index.js.map +1 -1
- package/dist/lib/handlers/callout-free-text.handler.d.ts +3 -0
- package/dist/lib/handlers/index.d.ts +1 -0
- package/dist/lib/handlers/types.d.ts +7 -1
- package/dist/lib/patching/index.d.ts +1 -0
- package/dist/lib/patching/patch-utils.d.ts +38 -1
- package/dist/lib/patching/patches/callout-freetext.patch.d.ts +3 -0
- package/dist/lib/patching/patches/index.d.ts +1 -0
- package/dist/lib/tools/default-tools.d.ts +35 -0
- package/dist/preact/index.cjs +1 -1
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.js +395 -14
- package/dist/preact/index.js.map +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +395 -14
- package/dist/react/index.js.map +1 -1
- package/dist/shared/components/annotations/callout-free-text-preview.d.ts +15 -0
- package/dist/shared/components/annotations/callout-free-text.d.ts +15 -0
- package/dist/shared-preact/components/annotations/callout-free-text-preview.d.ts +15 -0
- package/dist/shared-preact/components/annotations/callout-free-text.d.ts +15 -0
- package/dist/shared-react/components/annotations/callout-free-text-preview.d.ts +15 -0
- package/dist/shared-react/components/annotations/callout-free-text.d.ts +15 -0
- package/dist/svelte/components/annotations/CalloutFreeText.svelte.d.ts +15 -0
- package/dist/svelte/components/annotations/CalloutFreeTextPreview.svelte.d.ts +10 -0
- package/dist/svelte/components/renderers/CalloutFreeTextRenderer.svelte.d.ts +5 -0
- package/dist/svelte/index.cjs +1 -1
- package/dist/svelte/index.cjs.map +1 -1
- package/dist/svelte/index.js +497 -86
- package/dist/svelte/index.js.map +1 -1
- package/dist/vue/components/annotations/callout-free-text-preview.vue.d.ts +10 -0
- package/dist/vue/components/annotations/callout-free-text.vue.d.ts +25 -0
- package/dist/vue/components/renderers/callout-free-text-renderer.vue.d.ts +6 -0
- package/dist/vue/index.cjs +1 -1
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.js +544 -170
- package/dist/vue/index.js.map +1 -1
- package/package.json +12 -12
package/dist/index.js
CHANGED
|
@@ -737,6 +737,109 @@ function compensateRotatedVertexEdit(original, vertices, tightRect) {
|
|
|
737
737
|
if (Math.abs(qx) < 1e-8 && Math.abs(qy) < 1e-8) return vertices;
|
|
738
738
|
return vertices.map((v) => ({ x: v.x + qx, y: v.y + qy }));
|
|
739
739
|
}
|
|
740
|
+
function computeTextBoxFromRD(rect, rd) {
|
|
741
|
+
if (!rd) return rect;
|
|
742
|
+
return {
|
|
743
|
+
origin: { x: rect.origin.x + rd.left, y: rect.origin.y + rd.top },
|
|
744
|
+
size: {
|
|
745
|
+
width: Math.max(0, rect.size.width - rd.left - rd.right),
|
|
746
|
+
height: Math.max(0, rect.size.height - rd.top - rd.bottom)
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
function computeRDFromTextBox(overallRect, textBox) {
|
|
751
|
+
return {
|
|
752
|
+
left: textBox.origin.x - overallRect.origin.x,
|
|
753
|
+
top: textBox.origin.y - overallRect.origin.y,
|
|
754
|
+
right: overallRect.origin.x + overallRect.size.width - (textBox.origin.x + textBox.size.width),
|
|
755
|
+
bottom: overallRect.origin.y + overallRect.size.height - (textBox.origin.y + textBox.size.height)
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
function computeCalloutConnectionPoint(knee, textBox) {
|
|
759
|
+
const cx = textBox.origin.x + textBox.size.width / 2;
|
|
760
|
+
const cy = textBox.origin.y + textBox.size.height / 2;
|
|
761
|
+
const dx = knee.x - cx;
|
|
762
|
+
const dy = knee.y - cy;
|
|
763
|
+
if (Math.abs(dx) >= Math.abs(dy)) {
|
|
764
|
+
return dx > 0 ? { x: textBox.origin.x + textBox.size.width, y: cy } : { x: textBox.origin.x, y: cy };
|
|
765
|
+
}
|
|
766
|
+
return dy > 0 ? { x: cx, y: textBox.origin.y + textBox.size.height } : { x: cx, y: textBox.origin.y };
|
|
767
|
+
}
|
|
768
|
+
function computeCalloutOverallRect(textBox, calloutLine, lineEnding, strokeWidth) {
|
|
769
|
+
const linePoints = [...calloutLine];
|
|
770
|
+
if (lineEnding && calloutLine.length >= 2) {
|
|
771
|
+
const handler = LINE_ENDING_HANDLERS[lineEnding];
|
|
772
|
+
if (handler) {
|
|
773
|
+
const angle = Math.atan2(
|
|
774
|
+
calloutLine[1].y - calloutLine[0].y,
|
|
775
|
+
calloutLine[1].x - calloutLine[0].x
|
|
776
|
+
);
|
|
777
|
+
const localPts = handler.getLocalPoints(strokeWidth);
|
|
778
|
+
const rotationAngle = handler.getRotation(angle + Math.PI);
|
|
779
|
+
const transformed = localPts.map(
|
|
780
|
+
(p) => rotateAndTranslatePoint(p, rotationAngle, calloutLine[0])
|
|
781
|
+
);
|
|
782
|
+
linePoints.push(...transformed);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
const lineBbox = expandRect(rectFromPoints(linePoints), strokeWidth);
|
|
786
|
+
const tbRight = textBox.origin.x + textBox.size.width;
|
|
787
|
+
const tbBottom = textBox.origin.y + textBox.size.height;
|
|
788
|
+
const lnRight = lineBbox.origin.x + lineBbox.size.width;
|
|
789
|
+
const lnBottom = lineBbox.origin.y + lineBbox.size.height;
|
|
790
|
+
const minX = Math.min(textBox.origin.x, lineBbox.origin.x);
|
|
791
|
+
const minY = Math.min(textBox.origin.y, lineBbox.origin.y);
|
|
792
|
+
const maxX = Math.max(tbRight, lnRight);
|
|
793
|
+
const maxY = Math.max(tbBottom, lnBottom);
|
|
794
|
+
return {
|
|
795
|
+
origin: { x: minX, y: minY },
|
|
796
|
+
size: { width: maxX - minX, height: maxY - minY }
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
const calloutVertexConfig = {
|
|
800
|
+
extractVertices: (a) => {
|
|
801
|
+
const textBox = computeTextBoxFromRD(a.rect, a.rectangleDifferences);
|
|
802
|
+
const cl = a.calloutLine;
|
|
803
|
+
if (!cl || cl.length < 3) {
|
|
804
|
+
return [
|
|
805
|
+
{ x: a.rect.origin.x, y: a.rect.origin.y },
|
|
806
|
+
{ x: a.rect.origin.x, y: a.rect.origin.y },
|
|
807
|
+
{ x: textBox.origin.x, y: textBox.origin.y },
|
|
808
|
+
{ x: textBox.origin.x + textBox.size.width, y: textBox.origin.y + textBox.size.height }
|
|
809
|
+
];
|
|
810
|
+
}
|
|
811
|
+
return [
|
|
812
|
+
cl[0],
|
|
813
|
+
cl[1],
|
|
814
|
+
{ x: textBox.origin.x, y: textBox.origin.y },
|
|
815
|
+
{ x: textBox.origin.x + textBox.size.width, y: textBox.origin.y + textBox.size.height }
|
|
816
|
+
];
|
|
817
|
+
},
|
|
818
|
+
transformAnnotation: (a, vertices) => {
|
|
819
|
+
if (vertices.length < 4) return {};
|
|
820
|
+
const [arrowTip, knee, tbTL, tbBR] = vertices;
|
|
821
|
+
const textBox = {
|
|
822
|
+
origin: { x: Math.min(tbTL.x, tbBR.x), y: Math.min(tbTL.y, tbBR.y) },
|
|
823
|
+
size: {
|
|
824
|
+
width: Math.abs(tbBR.x - tbTL.x),
|
|
825
|
+
height: Math.abs(tbBR.y - tbTL.y)
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
const connectionPoint = computeCalloutConnectionPoint(knee, textBox);
|
|
829
|
+
const calloutLine = [arrowTip, knee, connectionPoint];
|
|
830
|
+
const overallRect = computeCalloutOverallRect(
|
|
831
|
+
textBox,
|
|
832
|
+
calloutLine,
|
|
833
|
+
a.lineEnding,
|
|
834
|
+
a.strokeWidth ?? 1
|
|
835
|
+
);
|
|
836
|
+
return {
|
|
837
|
+
calloutLine,
|
|
838
|
+
rect: overallRect,
|
|
839
|
+
rectangleDifferences: computeRDFromTextBox(overallRect, textBox)
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
};
|
|
740
843
|
function createEnding(ending, strokeWidth, rad, px, py) {
|
|
741
844
|
if (!ending) return null;
|
|
742
845
|
const handler = LINE_ENDING_HANDLERS[ending];
|
|
@@ -893,495 +996,252 @@ function clampAnnotationToPage(annotation, pageSize) {
|
|
|
893
996
|
} : {}
|
|
894
997
|
};
|
|
895
998
|
}
|
|
896
|
-
const
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
const
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
999
|
+
const patchInk = (original, ctx) => {
|
|
1000
|
+
switch (ctx.type) {
|
|
1001
|
+
case "vertex-edit":
|
|
1002
|
+
return ctx.changes;
|
|
1003
|
+
case "move": {
|
|
1004
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1005
|
+
const { dx, dy, rects } = baseMoveChanges(original, ctx.changes.rect);
|
|
1006
|
+
return {
|
|
1007
|
+
...rects,
|
|
1008
|
+
inkList: original.inkList.map((stroke) => ({
|
|
1009
|
+
points: stroke.points.map((p) => ({ x: p.x + dx, y: p.y + dy }))
|
|
1010
|
+
}))
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
case "resize": {
|
|
1014
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1015
|
+
const { scaleX, scaleY, oldRect, resolvedRect, rects } = baseResizeScaling(
|
|
1016
|
+
original,
|
|
1017
|
+
ctx.changes.rect,
|
|
1018
|
+
ctx.metadata
|
|
1019
|
+
);
|
|
1020
|
+
const inset = (r2, pad) => ({
|
|
1021
|
+
origin: { x: r2.origin.x + pad, y: r2.origin.y + pad },
|
|
1022
|
+
size: {
|
|
1023
|
+
width: Math.max(1, r2.size.width - pad * 2),
|
|
1024
|
+
height: Math.max(1, r2.size.height - pad * 2)
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
const resizeEpsilon = 1e-3;
|
|
1028
|
+
const widthChanged = Math.abs(scaleX - 1) > resizeEpsilon;
|
|
1029
|
+
const heightChanged = Math.abs(scaleY - 1) > resizeEpsilon;
|
|
1030
|
+
const strokeScale = widthChanged && !heightChanged ? scaleX : !widthChanged && heightChanged ? scaleY : Math.min(scaleX, scaleY);
|
|
1031
|
+
const rawStrokeWidth = Math.max(1, original.strokeWidth * strokeScale);
|
|
1032
|
+
const maxStrokeWidth = Math.max(
|
|
1033
|
+
1,
|
|
1034
|
+
Math.min(resolvedRect.size.width, resolvedRect.size.height)
|
|
1035
|
+
);
|
|
1036
|
+
const clampedStrokeWidth = Math.min(rawStrokeWidth, maxStrokeWidth);
|
|
1037
|
+
const newStrokeWidth = Number(clampedStrokeWidth.toFixed(1));
|
|
1038
|
+
const innerOld = inset(oldRect, original.strokeWidth / 2);
|
|
1039
|
+
const innerNew = inset(resolvedRect, newStrokeWidth / 2);
|
|
1040
|
+
const sx = innerNew.size.width / Math.max(innerOld.size.width, 1e-6);
|
|
1041
|
+
const sy = innerNew.size.height / Math.max(innerOld.size.height, 1e-6);
|
|
1042
|
+
return {
|
|
1043
|
+
...rects,
|
|
1044
|
+
inkList: original.inkList.map((stroke) => ({
|
|
1045
|
+
points: stroke.points.map((p) => ({
|
|
1046
|
+
x: innerNew.origin.x + (p.x - innerOld.origin.x) * sx,
|
|
1047
|
+
y: innerNew.origin.y + (p.y - innerOld.origin.y) * sy
|
|
1048
|
+
}))
|
|
1049
|
+
})),
|
|
1050
|
+
strokeWidth: newStrokeWidth
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
case "rotate": {
|
|
1054
|
+
const result = baseRotateChanges(original, ctx);
|
|
1055
|
+
if (!result) return ctx.changes;
|
|
1056
|
+
const { dx, dy } = rotateOrbitDelta(original, result);
|
|
1057
|
+
return {
|
|
1058
|
+
...result,
|
|
1059
|
+
inkList: original.inkList.map((stroke) => ({
|
|
1060
|
+
points: stroke.points.map((p) => ({ x: p.x + dx, y: p.y + dy }))
|
|
1061
|
+
}))
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
case "property-update": {
|
|
1065
|
+
const needsRectUpdate = ctx.changes.strokeWidth !== void 0 || ctx.changes.rotation !== void 0;
|
|
1066
|
+
if (!needsRectUpdate) return ctx.changes;
|
|
1067
|
+
const merged = { ...original, ...ctx.changes };
|
|
1068
|
+
const pts = merged.inkList.flatMap((s) => s.points);
|
|
1069
|
+
const tightRect = expandRect(rectFromPoints(pts), merged.strokeWidth / 2);
|
|
1070
|
+
const effectiveRotation = ctx.changes.rotation ?? original.rotation ?? 0;
|
|
1071
|
+
if (original.unrotatedRect || ctx.changes.rotation !== void 0) {
|
|
1072
|
+
return {
|
|
1073
|
+
...ctx.changes,
|
|
1074
|
+
unrotatedRect: tightRect,
|
|
1075
|
+
rect: calculateRotatedRectAABBAroundPoint(
|
|
1076
|
+
tightRect,
|
|
1077
|
+
effectiveRotation,
|
|
1078
|
+
resolveAnnotationRotationCenter(original)
|
|
1079
|
+
)
|
|
939
1080
|
};
|
|
940
|
-
anno = clampAnnotationToPage(anno, pageSize);
|
|
941
|
-
onCommit(anno);
|
|
942
1081
|
}
|
|
943
|
-
|
|
1082
|
+
return { ...ctx.changes, rect: tightRect };
|
|
1083
|
+
}
|
|
1084
|
+
default:
|
|
1085
|
+
return ctx.changes;
|
|
944
1086
|
}
|
|
945
1087
|
};
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
const start = getStartPos();
|
|
960
|
-
if (!start || getHasMoved()) return;
|
|
961
|
-
const distance2 = Math.sqrt(Math.pow(pos.x - start.x, 2) + Math.pow(pos.y - start.y, 2));
|
|
962
|
-
if (distance2 > threshold) {
|
|
963
|
-
setHasMoved(true);
|
|
1088
|
+
const patchLine = (orig, ctx) => {
|
|
1089
|
+
switch (ctx.type) {
|
|
1090
|
+
case "vertex-edit":
|
|
1091
|
+
if (ctx.changes.linePoints) {
|
|
1092
|
+
const { start, end } = ctx.changes.linePoints;
|
|
1093
|
+
const rawPoints = [start, end];
|
|
1094
|
+
const rawRect = lineRectWithEndings(rawPoints, orig.strokeWidth, orig.lineEndings);
|
|
1095
|
+
const compensated = compensateRotatedVertexEdit(orig, rawPoints, rawRect);
|
|
1096
|
+
const rect = lineRectWithEndings(compensated, orig.strokeWidth, orig.lineEndings);
|
|
1097
|
+
return {
|
|
1098
|
+
...resolveVertexEditRects(orig, rect),
|
|
1099
|
+
linePoints: { start: compensated[0], end: compensated[1] }
|
|
1100
|
+
};
|
|
964
1101
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
const
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1102
|
+
return ctx.changes;
|
|
1103
|
+
case "move": {
|
|
1104
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1105
|
+
const { dx, dy, rects } = baseMoveChanges(orig, ctx.changes.rect);
|
|
1106
|
+
return {
|
|
1107
|
+
...rects,
|
|
1108
|
+
linePoints: {
|
|
1109
|
+
start: { x: orig.linePoints.start.x + dx, y: orig.linePoints.start.y + dy },
|
|
1110
|
+
end: { x: orig.linePoints.end.x + dx, y: orig.linePoints.end.y + dy }
|
|
973
1111
|
}
|
|
974
|
-
}
|
|
975
|
-
setStartPos(null);
|
|
976
|
-
setHasMoved(false);
|
|
977
|
-
},
|
|
978
|
-
hasMoved: getHasMoved,
|
|
979
|
-
reset: () => {
|
|
980
|
-
setStartPos(null);
|
|
981
|
-
setHasMoved(false);
|
|
1112
|
+
};
|
|
982
1113
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
const clampToPage = (pos) => ({
|
|
991
|
-
x: clamp(pos.x, 0, pageSize.width),
|
|
992
|
-
y: clamp(pos.y, 0, pageSize.height)
|
|
993
|
-
});
|
|
994
|
-
const getDefaults = () => {
|
|
995
|
-
const tool = getTool();
|
|
996
|
-
if (!tool) return null;
|
|
1114
|
+
case "resize": {
|
|
1115
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1116
|
+
const { scaleX, scaleY, oldRect, resolvedRect, rects } = baseResizeScaling(
|
|
1117
|
+
orig,
|
|
1118
|
+
ctx.changes.rect,
|
|
1119
|
+
ctx.metadata
|
|
1120
|
+
);
|
|
997
1121
|
return {
|
|
998
|
-
...
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
};
|
|
1010
|
-
const clickDetector = useClickDetector({
|
|
1011
|
-
threshold: 5,
|
|
1012
|
-
getTool,
|
|
1013
|
-
onClickDetected: (pos, tool) => {
|
|
1014
|
-
var _a;
|
|
1015
|
-
const defaults = getDefaults();
|
|
1016
|
-
if (!defaults) return;
|
|
1017
|
-
const clickConfig = tool.clickBehavior;
|
|
1018
|
-
if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
|
|
1019
|
-
const { width, height } = clickConfig.defaultSize;
|
|
1020
|
-
const rect = {
|
|
1021
|
-
origin: { x: pos.x - width / 2, y: pos.y - height / 2 },
|
|
1022
|
-
size: { width, height }
|
|
1023
|
-
};
|
|
1024
|
-
const contents = clickConfig.defaultContent ?? defaults.contents;
|
|
1025
|
-
let anno = {
|
|
1026
|
-
...defaults,
|
|
1027
|
-
contents,
|
|
1028
|
-
type: PdfAnnotationSubtype.FREETEXT,
|
|
1029
|
-
rect,
|
|
1030
|
-
pageIndex,
|
|
1031
|
-
id: uuidV4(),
|
|
1032
|
-
created: /* @__PURE__ */ new Date()
|
|
1033
|
-
};
|
|
1034
|
-
if ((_a = tool.behavior) == null ? void 0 : _a.insertUpright) {
|
|
1035
|
-
anno = applyInsertUpright(anno, pageRotation, false);
|
|
1036
|
-
}
|
|
1037
|
-
anno = clampAnnotationToPage(anno, pageSize);
|
|
1038
|
-
onCommit(anno);
|
|
1039
|
-
}
|
|
1040
|
-
});
|
|
1041
|
-
const getPreview = (current) => {
|
|
1042
|
-
const start = getStart();
|
|
1043
|
-
if (!start) return null;
|
|
1044
|
-
const defaults = getDefaults();
|
|
1045
|
-
if (!defaults) return null;
|
|
1046
|
-
const minX = Math.min(start.x, current.x);
|
|
1047
|
-
const minY = Math.min(start.y, current.y);
|
|
1048
|
-
const width = Math.abs(start.x - current.x);
|
|
1049
|
-
const height = Math.abs(start.y - current.y);
|
|
1050
|
-
const rect = {
|
|
1051
|
-
origin: { x: minX, y: minY },
|
|
1052
|
-
size: { width, height }
|
|
1122
|
+
...rects,
|
|
1123
|
+
linePoints: {
|
|
1124
|
+
start: {
|
|
1125
|
+
x: resolvedRect.origin.x + (orig.linePoints.start.x - oldRect.origin.x) * scaleX,
|
|
1126
|
+
y: resolvedRect.origin.y + (orig.linePoints.start.y - oldRect.origin.y) * scaleY
|
|
1127
|
+
},
|
|
1128
|
+
end: {
|
|
1129
|
+
x: resolvedRect.origin.x + (orig.linePoints.end.x - oldRect.origin.x) * scaleX,
|
|
1130
|
+
y: resolvedRect.origin.y + (orig.linePoints.end.y - oldRect.origin.y) * scaleY
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1053
1133
|
};
|
|
1134
|
+
}
|
|
1135
|
+
case "rotate": {
|
|
1136
|
+
const result = baseRotateChanges(orig, ctx);
|
|
1137
|
+
if (!result) return ctx.changes;
|
|
1138
|
+
const { dx, dy } = rotateOrbitDelta(orig, result);
|
|
1054
1139
|
return {
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
rect
|
|
1140
|
+
...result,
|
|
1141
|
+
linePoints: {
|
|
1142
|
+
start: { x: orig.linePoints.start.x + dx, y: orig.linePoints.start.y + dy },
|
|
1143
|
+
end: { x: orig.linePoints.end.x + dx, y: orig.linePoints.end.y + dy }
|
|
1060
1144
|
}
|
|
1061
1145
|
};
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
const defaults = getDefaults();
|
|
1084
|
-
if (!defaults) return;
|
|
1085
|
-
const clampedPos = clampToPage(pos);
|
|
1086
|
-
if (!clickDetector.hasMoved()) {
|
|
1087
|
-
clickDetector.onEnd(clampedPos);
|
|
1088
|
-
} else {
|
|
1089
|
-
const minX = Math.min(start.x, clampedPos.x);
|
|
1090
|
-
const minY = Math.min(start.y, clampedPos.y);
|
|
1091
|
-
const width = Math.abs(start.x - clampedPos.x);
|
|
1092
|
-
const height = Math.abs(start.y - clampedPos.y);
|
|
1093
|
-
const rect = {
|
|
1094
|
-
origin: { x: minX, y: minY },
|
|
1095
|
-
size: { width, height }
|
|
1096
|
-
};
|
|
1097
|
-
const tool = getTool();
|
|
1098
|
-
let anno = {
|
|
1099
|
-
...defaults,
|
|
1100
|
-
type: PdfAnnotationSubtype.FREETEXT,
|
|
1101
|
-
rect,
|
|
1102
|
-
pageIndex: context.pageIndex,
|
|
1103
|
-
id: uuidV4(),
|
|
1104
|
-
created: /* @__PURE__ */ new Date()
|
|
1105
|
-
};
|
|
1106
|
-
if ((_a = tool == null ? void 0 : tool.behavior) == null ? void 0 : _a.insertUpright) {
|
|
1107
|
-
anno = applyInsertUpright(anno, pageRotation, true);
|
|
1108
|
-
}
|
|
1109
|
-
onCommit(anno);
|
|
1110
|
-
}
|
|
1111
|
-
setStart(null);
|
|
1112
|
-
onPreview(null);
|
|
1113
|
-
clickDetector.reset();
|
|
1114
|
-
(_b = evt.releasePointerCapture) == null ? void 0 : _b.call(evt);
|
|
1115
|
-
},
|
|
1116
|
-
onPointerLeave: (_, evt) => {
|
|
1117
|
-
var _a;
|
|
1118
|
-
setStart(null);
|
|
1119
|
-
onPreview(null);
|
|
1120
|
-
clickDetector.reset();
|
|
1121
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
1122
|
-
},
|
|
1123
|
-
onPointerCancel: (_, evt) => {
|
|
1124
|
-
var _a;
|
|
1125
|
-
setStart(null);
|
|
1126
|
-
onPreview(null);
|
|
1127
|
-
clickDetector.reset();
|
|
1128
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
1146
|
+
}
|
|
1147
|
+
case "property-update": {
|
|
1148
|
+
const needsRectUpdate = ctx.changes.strokeWidth !== void 0 || ctx.changes.lineEndings !== void 0 || ctx.changes.rotation !== void 0;
|
|
1149
|
+
if (!needsRectUpdate) return ctx.changes;
|
|
1150
|
+
const merged = { ...orig, ...ctx.changes };
|
|
1151
|
+
const tightRect = lineRectWithEndings(
|
|
1152
|
+
[merged.linePoints.start, merged.linePoints.end],
|
|
1153
|
+
merged.strokeWidth,
|
|
1154
|
+
merged.lineEndings
|
|
1155
|
+
);
|
|
1156
|
+
const effectiveRotation = ctx.changes.rotation ?? orig.rotation ?? 0;
|
|
1157
|
+
if (orig.unrotatedRect || ctx.changes.rotation !== void 0) {
|
|
1158
|
+
return {
|
|
1159
|
+
...ctx.changes,
|
|
1160
|
+
unrotatedRect: tightRect,
|
|
1161
|
+
rect: calculateRotatedRectAABBAroundPoint(
|
|
1162
|
+
tightRect,
|
|
1163
|
+
effectiveRotation,
|
|
1164
|
+
resolveAnnotationRotationCenter(orig)
|
|
1165
|
+
)
|
|
1166
|
+
};
|
|
1129
1167
|
}
|
|
1130
|
-
|
|
1168
|
+
return { ...ctx.changes, rect: tightRect };
|
|
1169
|
+
}
|
|
1170
|
+
default:
|
|
1171
|
+
return ctx.changes;
|
|
1131
1172
|
}
|
|
1132
1173
|
};
|
|
1133
|
-
const
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1174
|
+
const patchPolyline = (orig, ctx) => {
|
|
1175
|
+
switch (ctx.type) {
|
|
1176
|
+
case "vertex-edit":
|
|
1177
|
+
if (ctx.changes.vertices && ctx.changes.vertices.length) {
|
|
1178
|
+
const rawVertices = ctx.changes.vertices;
|
|
1179
|
+
const rawRect = lineRectWithEndings(rawVertices, orig.strokeWidth, orig.lineEndings);
|
|
1180
|
+
const compensated = compensateRotatedVertexEdit(orig, rawVertices, rawRect);
|
|
1181
|
+
const rect = lineRectWithEndings(compensated, orig.strokeWidth, orig.lineEndings);
|
|
1182
|
+
return {
|
|
1183
|
+
...resolveVertexEditRects(orig, rect),
|
|
1184
|
+
vertices: compensated
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
return ctx.changes;
|
|
1188
|
+
case "move": {
|
|
1189
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1190
|
+
const { dx, dy, rects } = baseMoveChanges(orig, ctx.changes.rect);
|
|
1145
1191
|
return {
|
|
1146
|
-
...
|
|
1147
|
-
|
|
1148
|
-
lineEndings: tool.defaults.lineEndings ?? {
|
|
1149
|
-
start: PdfAnnotationLineEnding.None,
|
|
1150
|
-
end: PdfAnnotationLineEnding.None
|
|
1151
|
-
},
|
|
1152
|
-
color: tool.defaults.color ?? "#000000",
|
|
1153
|
-
opacity: tool.defaults.opacity ?? 1,
|
|
1154
|
-
strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
|
|
1155
|
-
strokeDashArray: tool.defaults.strokeDashArray ?? [],
|
|
1156
|
-
strokeColor: tool.defaults.strokeColor ?? "#000000",
|
|
1157
|
-
flags: tool.defaults.flags ?? ["print"]
|
|
1192
|
+
...rects,
|
|
1193
|
+
vertices: orig.vertices.map((p) => ({ x: p.x + dx, y: p.y + dy }))
|
|
1158
1194
|
};
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
const clickConfig = tool.clickBehavior;
|
|
1167
|
-
if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
|
|
1168
|
-
const angle = clickConfig.defaultAngle ?? 0;
|
|
1169
|
-
const length = clickConfig.defaultLength;
|
|
1170
|
-
const halfLength = length / 2;
|
|
1171
|
-
const startX = pos.x - halfLength * Math.cos(angle);
|
|
1172
|
-
const startY = pos.y - halfLength * Math.sin(angle);
|
|
1173
|
-
const endX = pos.x + halfLength * Math.cos(angle);
|
|
1174
|
-
const endY = pos.y + halfLength * Math.sin(angle);
|
|
1175
|
-
const start = clampToPage({ x: startX, y: startY });
|
|
1176
|
-
const end = clampToPage({ x: endX, y: endY });
|
|
1177
|
-
const rect = lineRectWithEndings(
|
|
1178
|
-
[start, end],
|
|
1179
|
-
defaults.strokeWidth,
|
|
1180
|
-
defaults.lineEndings
|
|
1181
|
-
);
|
|
1182
|
-
onCommit({
|
|
1183
|
-
...defaults,
|
|
1184
|
-
rect,
|
|
1185
|
-
linePoints: { start, end },
|
|
1186
|
-
pageIndex,
|
|
1187
|
-
id: uuidV4(),
|
|
1188
|
-
created: /* @__PURE__ */ new Date(),
|
|
1189
|
-
type: PdfAnnotationSubtype.LINE
|
|
1190
|
-
});
|
|
1191
|
-
}
|
|
1192
|
-
});
|
|
1193
|
-
const getPreview = (current) => {
|
|
1194
|
-
const start = getStart();
|
|
1195
|
-
if (!start) return null;
|
|
1196
|
-
const defaults = getDefaults();
|
|
1197
|
-
if (!defaults) return null;
|
|
1198
|
-
const bounds = lineRectWithEndings(
|
|
1199
|
-
[start, current],
|
|
1200
|
-
defaults.strokeWidth,
|
|
1201
|
-
defaults.lineEndings
|
|
1195
|
+
}
|
|
1196
|
+
case "resize": {
|
|
1197
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1198
|
+
const { scaleX, scaleY, oldRect, resolvedRect, rects } = baseResizeScaling(
|
|
1199
|
+
orig,
|
|
1200
|
+
ctx.changes.rect,
|
|
1201
|
+
ctx.metadata
|
|
1202
1202
|
);
|
|
1203
1203
|
return {
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
linePoints: { start, end: current }
|
|
1210
|
-
}
|
|
1204
|
+
...rects,
|
|
1205
|
+
vertices: orig.vertices.map((v) => ({
|
|
1206
|
+
x: resolvedRect.origin.x + (v.x - oldRect.origin.x) * scaleX,
|
|
1207
|
+
y: resolvedRect.origin.y + (v.y - oldRect.origin.y) * scaleY
|
|
1208
|
+
}))
|
|
1211
1209
|
};
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
setStart(clampedPos);
|
|
1218
|
-
clickDetector.onStart(clampedPos);
|
|
1219
|
-
onPreview(getPreview(clampedPos));
|
|
1220
|
-
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
1221
|
-
},
|
|
1222
|
-
onPointerMove: (pos) => {
|
|
1223
|
-
const clampedPos = clampToPage(pos);
|
|
1224
|
-
clickDetector.onMove(clampedPos);
|
|
1225
|
-
if (getStart() && clickDetector.hasMoved()) {
|
|
1226
|
-
onPreview(getPreview(clampedPos));
|
|
1227
|
-
}
|
|
1228
|
-
},
|
|
1229
|
-
onPointerUp: (pos, evt) => {
|
|
1230
|
-
var _a;
|
|
1231
|
-
const start = getStart();
|
|
1232
|
-
if (!start) return;
|
|
1233
|
-
const clampedPos = clampToPage(pos);
|
|
1234
|
-
if (!clickDetector.hasMoved()) {
|
|
1235
|
-
clickDetector.onEnd(clampedPos);
|
|
1236
|
-
} else {
|
|
1237
|
-
const defaults = getDefaults();
|
|
1238
|
-
if (!defaults) return;
|
|
1239
|
-
if (Math.abs(clampedPos.x - start.x) > 2 || Math.abs(clampedPos.y - start.y) > 2) {
|
|
1240
|
-
const rect = lineRectWithEndings(
|
|
1241
|
-
[start, clampedPos],
|
|
1242
|
-
defaults.strokeWidth,
|
|
1243
|
-
defaults.lineEndings
|
|
1244
|
-
);
|
|
1245
|
-
onCommit({
|
|
1246
|
-
...defaults,
|
|
1247
|
-
rect,
|
|
1248
|
-
linePoints: { start, end: clampedPos },
|
|
1249
|
-
pageIndex,
|
|
1250
|
-
id: uuidV4(),
|
|
1251
|
-
flags: ["print"],
|
|
1252
|
-
created: /* @__PURE__ */ new Date(),
|
|
1253
|
-
type: PdfAnnotationSubtype.LINE
|
|
1254
|
-
});
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
setStart(null);
|
|
1258
|
-
onPreview(null);
|
|
1259
|
-
clickDetector.reset();
|
|
1260
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
1261
|
-
},
|
|
1262
|
-
onPointerLeave: (_, evt) => {
|
|
1263
|
-
var _a;
|
|
1264
|
-
setStart(null);
|
|
1265
|
-
onPreview(null);
|
|
1266
|
-
clickDetector.reset();
|
|
1267
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
1268
|
-
},
|
|
1269
|
-
onPointerCancel: (_, evt) => {
|
|
1270
|
-
var _a;
|
|
1271
|
-
setStart(null);
|
|
1272
|
-
onPreview(null);
|
|
1273
|
-
clickDetector.reset();
|
|
1274
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
1275
|
-
}
|
|
1276
|
-
};
|
|
1277
|
-
}
|
|
1278
|
-
};
|
|
1279
|
-
const polylineHandlerFactory = {
|
|
1280
|
-
annotationType: PdfAnnotationSubtype.POLYLINE,
|
|
1281
|
-
create(context) {
|
|
1282
|
-
const { onCommit, onPreview, getTool, pageSize } = context;
|
|
1283
|
-
const [getVertices, setVertices] = useState([]);
|
|
1284
|
-
const [getCurrent, setCurrent] = useState(null);
|
|
1285
|
-
const clampToPage = (pos) => ({
|
|
1286
|
-
x: clamp(pos.x, 0, pageSize.width),
|
|
1287
|
-
y: clamp(pos.y, 0, pageSize.height)
|
|
1288
|
-
});
|
|
1289
|
-
const getDefaults = () => {
|
|
1290
|
-
const tool = getTool();
|
|
1291
|
-
if (!tool) return null;
|
|
1210
|
+
}
|
|
1211
|
+
case "rotate": {
|
|
1212
|
+
const result = baseRotateChanges(orig, ctx);
|
|
1213
|
+
if (!result) return ctx.changes;
|
|
1214
|
+
const { dx, dy } = rotateOrbitDelta(orig, result);
|
|
1292
1215
|
return {
|
|
1293
|
-
...
|
|
1294
|
-
|
|
1295
|
-
lineEndings: tool.defaults.lineEndings ?? {
|
|
1296
|
-
start: PdfAnnotationLineEnding.None,
|
|
1297
|
-
end: PdfAnnotationLineEnding.None
|
|
1298
|
-
},
|
|
1299
|
-
color: tool.defaults.color ?? "#000000",
|
|
1300
|
-
opacity: tool.defaults.opacity ?? 1,
|
|
1301
|
-
strokeColor: tool.defaults.strokeColor ?? "#000000",
|
|
1302
|
-
strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
|
|
1303
|
-
strokeDashArray: tool.defaults.strokeDashArray ?? [],
|
|
1304
|
-
flags: tool.defaults.flags ?? ["print"]
|
|
1305
|
-
};
|
|
1306
|
-
};
|
|
1307
|
-
const commitPolyline = () => {
|
|
1308
|
-
const vertices = getVertices();
|
|
1309
|
-
if (vertices.length < 2) return;
|
|
1310
|
-
const defaults = getDefaults();
|
|
1311
|
-
if (!defaults) return;
|
|
1312
|
-
const rect = lineRectWithEndings(
|
|
1313
|
-
vertices,
|
|
1314
|
-
defaults.strokeWidth,
|
|
1315
|
-
defaults.lineEndings
|
|
1316
|
-
);
|
|
1317
|
-
const anno = {
|
|
1318
|
-
...defaults,
|
|
1319
|
-
vertices,
|
|
1320
|
-
rect,
|
|
1321
|
-
type: PdfAnnotationSubtype.POLYLINE,
|
|
1322
|
-
pageIndex: context.pageIndex,
|
|
1323
|
-
id: uuidV4(),
|
|
1324
|
-
created: /* @__PURE__ */ new Date()
|
|
1216
|
+
...result,
|
|
1217
|
+
vertices: orig.vertices.map((v) => ({ x: v.x + dx, y: v.y + dy }))
|
|
1325
1218
|
};
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
const defaults = getDefaults();
|
|
1336
|
-
if (!defaults) return null;
|
|
1337
|
-
const allPoints = [...vertices, currentPos];
|
|
1338
|
-
const bounds = lineRectWithEndings(
|
|
1339
|
-
allPoints,
|
|
1340
|
-
defaults.strokeWidth,
|
|
1341
|
-
defaults.lineEndings
|
|
1219
|
+
}
|
|
1220
|
+
case "property-update": {
|
|
1221
|
+
const needsRectUpdate = ctx.changes.strokeWidth !== void 0 || ctx.changes.lineEndings !== void 0 || ctx.changes.rotation !== void 0;
|
|
1222
|
+
if (!needsRectUpdate) return ctx.changes;
|
|
1223
|
+
const merged = { ...orig, ...ctx.changes };
|
|
1224
|
+
const tightRect = lineRectWithEndings(
|
|
1225
|
+
merged.vertices,
|
|
1226
|
+
merged.strokeWidth,
|
|
1227
|
+
merged.lineEndings
|
|
1342
1228
|
);
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
rect:
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
return {
|
|
1355
|
-
onClick: (pos, evt) => {
|
|
1356
|
-
if (evt.metaKey || evt.ctrlKey) {
|
|
1357
|
-
return;
|
|
1358
|
-
}
|
|
1359
|
-
const clampedPos = clampToPage(pos);
|
|
1360
|
-
const vertices = getVertices();
|
|
1361
|
-
const lastVertex = vertices[vertices.length - 1];
|
|
1362
|
-
if (lastVertex && Math.abs(lastVertex.x - clampedPos.x) < 1 && Math.abs(lastVertex.y - clampedPos.y) < 1) {
|
|
1363
|
-
return;
|
|
1364
|
-
}
|
|
1365
|
-
setVertices([...vertices, clampedPos]);
|
|
1366
|
-
setCurrent(clampedPos);
|
|
1367
|
-
onPreview(getPreview());
|
|
1368
|
-
},
|
|
1369
|
-
onDoubleClick: () => {
|
|
1370
|
-
commitPolyline();
|
|
1371
|
-
},
|
|
1372
|
-
onPointerMove: (pos) => {
|
|
1373
|
-
if (getVertices().length > 0) {
|
|
1374
|
-
const clampedPos = clampToPage(pos);
|
|
1375
|
-
setCurrent(clampedPos);
|
|
1376
|
-
onPreview(getPreview());
|
|
1377
|
-
}
|
|
1378
|
-
},
|
|
1379
|
-
onPointerCancel: () => {
|
|
1380
|
-
setVertices([]);
|
|
1381
|
-
setCurrent(null);
|
|
1382
|
-
onPreview(null);
|
|
1229
|
+
const effectiveRotation = ctx.changes.rotation ?? orig.rotation ?? 0;
|
|
1230
|
+
if (orig.unrotatedRect || ctx.changes.rotation !== void 0) {
|
|
1231
|
+
return {
|
|
1232
|
+
...ctx.changes,
|
|
1233
|
+
unrotatedRect: tightRect,
|
|
1234
|
+
rect: calculateRotatedRectAABBAroundPoint(
|
|
1235
|
+
tightRect,
|
|
1236
|
+
effectiveRotation,
|
|
1237
|
+
resolveAnnotationRotationCenter(orig)
|
|
1238
|
+
)
|
|
1239
|
+
};
|
|
1383
1240
|
}
|
|
1384
|
-
|
|
1241
|
+
return { ...ctx.changes, rect: tightRect };
|
|
1242
|
+
}
|
|
1243
|
+
default:
|
|
1244
|
+
return ctx.changes;
|
|
1385
1245
|
}
|
|
1386
1246
|
};
|
|
1387
1247
|
function convertAABBRectToUnrotatedSpace(newAABBRect, originalAABBRect, originalUnrotatedRect, rotationDegrees) {
|
|
@@ -1932,204 +1792,462 @@ function generateCloudyPolygonPath(vertices, rectOrigin, intensity, lineWidth) {
|
|
|
1932
1792
|
out.close();
|
|
1933
1793
|
return out.build(lineWidth);
|
|
1934
1794
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1795
|
+
function getPolygonPad(intensity, strokeWidth) {
|
|
1796
|
+
if ((intensity ?? 0) > 0) {
|
|
1797
|
+
return getCloudyBorderExtent(intensity, strokeWidth, false);
|
|
1798
|
+
}
|
|
1799
|
+
return strokeWidth / 2;
|
|
1800
|
+
}
|
|
1801
|
+
const patchPolygon = (orig, ctx) => {
|
|
1802
|
+
switch (ctx.type) {
|
|
1803
|
+
case "vertex-edit":
|
|
1804
|
+
if (ctx.changes.vertices && ctx.changes.vertices.length) {
|
|
1805
|
+
const pad = getPolygonPad(orig.cloudyBorderIntensity, orig.strokeWidth);
|
|
1806
|
+
const rawVertices = ctx.changes.vertices;
|
|
1807
|
+
const rawRect = expandRect(rectFromPoints(rawVertices), pad);
|
|
1808
|
+
const compensated = compensateRotatedVertexEdit(orig, rawVertices, rawRect);
|
|
1809
|
+
const rect = expandRect(rectFromPoints(compensated), pad);
|
|
1810
|
+
return {
|
|
1811
|
+
...resolveVertexEditRects(orig, rect),
|
|
1812
|
+
vertices: compensated
|
|
1813
|
+
};
|
|
1814
|
+
}
|
|
1815
|
+
return ctx.changes;
|
|
1816
|
+
case "move": {
|
|
1817
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1818
|
+
const { dx, dy, rects } = baseMoveChanges(orig, ctx.changes.rect);
|
|
1957
1819
|
return {
|
|
1958
|
-
...
|
|
1959
|
-
|
|
1960
|
-
opacity: tool.defaults.opacity ?? 1,
|
|
1961
|
-
strokeWidth: tool.defaults.strokeWidth ?? 1,
|
|
1962
|
-
strokeColor: tool.defaults.strokeColor ?? "#000000",
|
|
1963
|
-
strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
|
|
1964
|
-
strokeDashArray: tool.defaults.strokeDashArray ?? [],
|
|
1965
|
-
flags: tool.defaults.flags ?? ["print"]
|
|
1820
|
+
...rects,
|
|
1821
|
+
vertices: orig.vertices.map((p) => ({ x: p.x + dx, y: p.y + dy }))
|
|
1966
1822
|
};
|
|
1967
|
-
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
pageIndex: context.pageIndex,
|
|
1982
|
-
id: uuidV4(),
|
|
1983
|
-
created: /* @__PURE__ */ new Date(),
|
|
1984
|
-
...intensity > 0 && {
|
|
1985
|
-
rectangleDifferences: { left: pad, top: pad, right: pad, bottom: pad }
|
|
1986
|
-
}
|
|
1823
|
+
}
|
|
1824
|
+
case "resize": {
|
|
1825
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1826
|
+
const { scaleX, scaleY, oldRect, resolvedRect, rects } = baseResizeScaling(
|
|
1827
|
+
orig,
|
|
1828
|
+
ctx.changes.rect,
|
|
1829
|
+
ctx.metadata
|
|
1830
|
+
);
|
|
1831
|
+
return {
|
|
1832
|
+
...rects,
|
|
1833
|
+
vertices: orig.vertices.map((v) => ({
|
|
1834
|
+
x: resolvedRect.origin.x + (v.x - oldRect.origin.x) * scaleX,
|
|
1835
|
+
y: resolvedRect.origin.y + (v.y - oldRect.origin.y) * scaleY
|
|
1836
|
+
}))
|
|
1987
1837
|
};
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
const getPreview = () => {
|
|
1994
|
-
const vertices = getVertices();
|
|
1995
|
-
const currentPos = getCurrent();
|
|
1996
|
-
if (vertices.length === 0 || !currentPos) return null;
|
|
1997
|
-
const defaults = getDefaults();
|
|
1998
|
-
if (!defaults) return null;
|
|
1999
|
-
const intensity = defaults.cloudyBorderIntensity ?? 0;
|
|
2000
|
-
const pad = intensity > 0 ? getCloudyBorderExtent(intensity, defaults.strokeWidth, false) : defaults.strokeWidth / 2;
|
|
2001
|
-
const allPoints = [...vertices, currentPos];
|
|
2002
|
-
const bounds = expandRect(rectFromPoints(allPoints), pad);
|
|
1838
|
+
}
|
|
1839
|
+
case "rotate": {
|
|
1840
|
+
const result = baseRotateChanges(orig, ctx);
|
|
1841
|
+
if (!result) return ctx.changes;
|
|
1842
|
+
const { dx, dy } = rotateOrbitDelta(orig, result);
|
|
2003
1843
|
return {
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
data: {
|
|
2007
|
-
...defaults,
|
|
2008
|
-
rect: bounds,
|
|
2009
|
-
vertices,
|
|
2010
|
-
currentVertex: currentPos
|
|
2011
|
-
}
|
|
1844
|
+
...result,
|
|
1845
|
+
vertices: orig.vertices.map((v) => ({ x: v.x + dx, y: v.y + dy }))
|
|
2012
1846
|
};
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
1847
|
+
}
|
|
1848
|
+
case "property-update": {
|
|
1849
|
+
const cloudyChanged = ctx.changes.cloudyBorderIntensity !== void 0;
|
|
1850
|
+
const needsRectUpdate = ctx.changes.strokeWidth !== void 0 || ctx.changes.rotation !== void 0 || cloudyChanged;
|
|
1851
|
+
if (!needsRectUpdate) return ctx.changes;
|
|
1852
|
+
const merged = { ...orig, ...ctx.changes };
|
|
1853
|
+
const pad = getPolygonPad(merged.cloudyBorderIntensity, merged.strokeWidth);
|
|
1854
|
+
const tightRect = expandRect(rectFromPoints(merged.vertices), pad);
|
|
1855
|
+
let patch = ctx.changes;
|
|
1856
|
+
const hasCloudy = (orig.cloudyBorderIntensity ?? 0) > 0;
|
|
1857
|
+
if (cloudyChanged || ctx.changes.strokeWidth !== void 0 && hasCloudy) {
|
|
1858
|
+
const intensity = merged.cloudyBorderIntensity ?? 0;
|
|
1859
|
+
if (intensity > 0) {
|
|
1860
|
+
const extent = getCloudyBorderExtent(intensity, merged.strokeWidth, false);
|
|
1861
|
+
patch = {
|
|
1862
|
+
...patch,
|
|
1863
|
+
rectangleDifferences: { left: extent, top: extent, right: extent, bottom: extent }
|
|
1864
|
+
};
|
|
1865
|
+
} else {
|
|
1866
|
+
patch = { ...patch, rectangleDifferences: void 0 };
|
|
2023
1867
|
}
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
1868
|
+
}
|
|
1869
|
+
const effectiveRotation = ctx.changes.rotation ?? orig.rotation ?? 0;
|
|
1870
|
+
if (orig.unrotatedRect || ctx.changes.rotation !== void 0) {
|
|
1871
|
+
return {
|
|
1872
|
+
...patch,
|
|
1873
|
+
unrotatedRect: tightRect,
|
|
1874
|
+
rect: calculateRotatedRectAABBAroundPoint(
|
|
1875
|
+
tightRect,
|
|
1876
|
+
effectiveRotation,
|
|
1877
|
+
resolveAnnotationRotationCenter(orig)
|
|
1878
|
+
)
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
return { ...patch, rect: tightRect };
|
|
1882
|
+
}
|
|
1883
|
+
default:
|
|
1884
|
+
return ctx.changes;
|
|
1885
|
+
}
|
|
1886
|
+
};
|
|
1887
|
+
const patchCircle = (orig, ctx) => {
|
|
1888
|
+
switch (ctx.type) {
|
|
1889
|
+
case "move":
|
|
1890
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1891
|
+
return baseMoveChanges(orig, ctx.changes.rect).rects;
|
|
1892
|
+
case "resize":
|
|
1893
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1894
|
+
return baseResizeScaling(orig, ctx.changes.rect, ctx.metadata).rects;
|
|
1895
|
+
case "rotate":
|
|
1896
|
+
return baseRotateChanges(orig, ctx) ?? ctx.changes;
|
|
1897
|
+
case "property-update": {
|
|
1898
|
+
let patch = ctx.changes;
|
|
1899
|
+
const cloudyChanged = ctx.changes.cloudyBorderIntensity !== void 0;
|
|
1900
|
+
const strokeChanged = ctx.changes.strokeWidth !== void 0;
|
|
1901
|
+
const hasCloudy = (orig.cloudyBorderIntensity ?? 0) > 0;
|
|
1902
|
+
if (cloudyChanged || strokeChanged && hasCloudy) {
|
|
1903
|
+
const merged = { ...orig, ...ctx.changes };
|
|
1904
|
+
const intensity = merged.cloudyBorderIntensity ?? 0;
|
|
1905
|
+
if (intensity > 0) {
|
|
1906
|
+
const extent = getCloudyBorderExtent(intensity, merged.strokeWidth, true);
|
|
1907
|
+
patch = {
|
|
1908
|
+
...patch,
|
|
1909
|
+
rectangleDifferences: { left: extent, top: extent, right: extent, bottom: extent }
|
|
1910
|
+
};
|
|
1911
|
+
} else {
|
|
1912
|
+
patch = { ...patch, rectangleDifferences: void 0 };
|
|
2028
1913
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
1914
|
+
}
|
|
1915
|
+
if (ctx.changes.rotation !== void 0) {
|
|
1916
|
+
patch = { ...patch, ...basePropertyRotationChanges(orig, ctx.changes.rotation) };
|
|
1917
|
+
}
|
|
1918
|
+
return patch;
|
|
1919
|
+
}
|
|
1920
|
+
default:
|
|
1921
|
+
return ctx.changes;
|
|
1922
|
+
}
|
|
1923
|
+
};
|
|
1924
|
+
const patchSquare = (orig, ctx) => {
|
|
1925
|
+
switch (ctx.type) {
|
|
1926
|
+
case "move":
|
|
1927
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1928
|
+
return baseMoveChanges(orig, ctx.changes.rect).rects;
|
|
1929
|
+
case "resize":
|
|
1930
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1931
|
+
return baseResizeScaling(orig, ctx.changes.rect, ctx.metadata).rects;
|
|
1932
|
+
case "rotate":
|
|
1933
|
+
return baseRotateChanges(orig, ctx) ?? ctx.changes;
|
|
1934
|
+
case "property-update": {
|
|
1935
|
+
let patch = ctx.changes;
|
|
1936
|
+
const cloudyChanged = ctx.changes.cloudyBorderIntensity !== void 0;
|
|
1937
|
+
const strokeChanged = ctx.changes.strokeWidth !== void 0;
|
|
1938
|
+
const hasCloudy = (orig.cloudyBorderIntensity ?? 0) > 0;
|
|
1939
|
+
if (cloudyChanged || strokeChanged && hasCloudy) {
|
|
1940
|
+
const merged = { ...orig, ...ctx.changes };
|
|
1941
|
+
const intensity = merged.cloudyBorderIntensity ?? 0;
|
|
1942
|
+
if (intensity > 0) {
|
|
1943
|
+
const extent = getCloudyBorderExtent(intensity, merged.strokeWidth, false);
|
|
1944
|
+
patch = {
|
|
1945
|
+
...patch,
|
|
1946
|
+
rectangleDifferences: { left: extent, top: extent, right: extent, bottom: extent }
|
|
1947
|
+
};
|
|
1948
|
+
} else {
|
|
1949
|
+
patch = { ...patch, rectangleDifferences: void 0 };
|
|
2041
1950
|
}
|
|
2042
|
-
},
|
|
2043
|
-
onPointerCancel: (_) => {
|
|
2044
|
-
setVertices([]);
|
|
2045
|
-
setCurrent(null);
|
|
2046
|
-
onPreview(null);
|
|
2047
1951
|
}
|
|
2048
|
-
|
|
1952
|
+
if (ctx.changes.rotation !== void 0) {
|
|
1953
|
+
patch = { ...patch, ...basePropertyRotationChanges(orig, ctx.changes.rotation) };
|
|
1954
|
+
}
|
|
1955
|
+
return patch;
|
|
1956
|
+
}
|
|
1957
|
+
default:
|
|
1958
|
+
return ctx.changes;
|
|
2049
1959
|
}
|
|
2050
1960
|
};
|
|
2051
|
-
const
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
if (
|
|
1961
|
+
const patchFreeText = (orig, ctx) => {
|
|
1962
|
+
switch (ctx.type) {
|
|
1963
|
+
case "move":
|
|
1964
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1965
|
+
return baseMoveChanges(orig, ctx.changes.rect).rects;
|
|
1966
|
+
case "resize":
|
|
1967
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
1968
|
+
return baseResizeScaling(orig, ctx.changes.rect, ctx.metadata).rects;
|
|
1969
|
+
case "rotate":
|
|
1970
|
+
return baseRotateChanges(orig, ctx) ?? ctx.changes;
|
|
1971
|
+
case "property-update":
|
|
1972
|
+
if (ctx.changes.rotation !== void 0) {
|
|
1973
|
+
return { ...ctx.changes, ...basePropertyRotationChanges(orig, ctx.changes.rotation) };
|
|
1974
|
+
}
|
|
1975
|
+
return ctx.changes;
|
|
1976
|
+
default:
|
|
1977
|
+
return ctx.changes;
|
|
1978
|
+
}
|
|
1979
|
+
};
|
|
1980
|
+
function rebuildFromVertices(orig, arrowTip, knee, tbTL, tbBR) {
|
|
1981
|
+
const textBox = {
|
|
1982
|
+
origin: { x: Math.min(tbTL.x, tbBR.x), y: Math.min(tbTL.y, tbBR.y) },
|
|
1983
|
+
size: {
|
|
1984
|
+
width: Math.abs(tbBR.x - tbTL.x),
|
|
1985
|
+
height: Math.abs(tbBR.y - tbTL.y)
|
|
1986
|
+
}
|
|
1987
|
+
};
|
|
1988
|
+
const connectionPoint = computeCalloutConnectionPoint(knee, textBox);
|
|
1989
|
+
const calloutLine = [arrowTip, knee, connectionPoint];
|
|
1990
|
+
const overallRect = computeCalloutOverallRect(
|
|
1991
|
+
textBox,
|
|
1992
|
+
calloutLine,
|
|
1993
|
+
orig.lineEnding,
|
|
1994
|
+
orig.strokeWidth ?? 1
|
|
1995
|
+
);
|
|
1996
|
+
return {
|
|
1997
|
+
calloutLine,
|
|
1998
|
+
rect: overallRect,
|
|
1999
|
+
rectangleDifferences: computeRDFromTextBox(overallRect, textBox)
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
const patchCalloutFreeText = (orig, ctx) => {
|
|
2003
|
+
var _a, _b;
|
|
2004
|
+
switch (ctx.type) {
|
|
2005
|
+
case "vertex-edit": {
|
|
2006
|
+
if (!ctx.changes.calloutLine) return ctx.changes;
|
|
2007
|
+
const verts = ctx.changes.calloutLine;
|
|
2008
|
+
if (verts.length < 4) return ctx.changes;
|
|
2009
|
+
return rebuildFromVertices(orig, verts[0], verts[1], verts[2], verts[3]);
|
|
2010
|
+
}
|
|
2011
|
+
case "move": {
|
|
2012
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
2013
|
+
const { dx, dy, rects } = baseMoveChanges(orig, ctx.changes.rect);
|
|
2014
|
+
const movedLine = (_a = orig.calloutLine) == null ? void 0 : _a.map((p) => ({ x: p.x + dx, y: p.y + dy }));
|
|
2063
2015
|
return {
|
|
2064
|
-
...
|
|
2065
|
-
|
|
2066
|
-
strokeWidth: tool.defaults.strokeWidth ?? 2,
|
|
2067
|
-
strokeColor: tool.defaults.strokeColor ?? "#000000",
|
|
2068
|
-
strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
|
|
2069
|
-
strokeDashArray: tool.defaults.strokeDashArray ?? [],
|
|
2070
|
-
color: tool.defaults.color ?? "#000000",
|
|
2071
|
-
opacity: tool.defaults.opacity ?? 1
|
|
2016
|
+
...rects,
|
|
2017
|
+
...movedLine && { calloutLine: movedLine }
|
|
2072
2018
|
};
|
|
2073
|
-
}
|
|
2019
|
+
}
|
|
2020
|
+
case "rotate": {
|
|
2021
|
+
const result = baseRotateChanges(orig, ctx);
|
|
2022
|
+
if (!result) return ctx.changes;
|
|
2023
|
+
const { dx, dy } = rotateOrbitDelta(orig, result);
|
|
2024
|
+
const movedLine = (_b = orig.calloutLine) == null ? void 0 : _b.map((p) => ({ x: p.x + dx, y: p.y + dy }));
|
|
2025
|
+
return {
|
|
2026
|
+
...result,
|
|
2027
|
+
...movedLine && { calloutLine: movedLine }
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
case "property-update": {
|
|
2031
|
+
if (ctx.changes.lineEnding !== void 0 || ctx.changes.strokeWidth !== void 0) {
|
|
2032
|
+
const merged = { ...orig, ...ctx.changes };
|
|
2033
|
+
if (merged.calloutLine && merged.calloutLine.length >= 3) {
|
|
2034
|
+
const textBox = computeTextBoxFromRD(orig.rect, orig.rectangleDifferences);
|
|
2035
|
+
const overallRect = computeCalloutOverallRect(
|
|
2036
|
+
textBox,
|
|
2037
|
+
merged.calloutLine,
|
|
2038
|
+
merged.lineEnding,
|
|
2039
|
+
merged.strokeWidth ?? 1
|
|
2040
|
+
);
|
|
2041
|
+
return {
|
|
2042
|
+
...ctx.changes,
|
|
2043
|
+
rect: overallRect,
|
|
2044
|
+
rectangleDifferences: computeRDFromTextBox(overallRect, textBox)
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
return ctx.changes;
|
|
2049
|
+
}
|
|
2050
|
+
default:
|
|
2051
|
+
return ctx.changes;
|
|
2052
|
+
}
|
|
2053
|
+
};
|
|
2054
|
+
const patchStamp = (orig, ctx) => {
|
|
2055
|
+
switch (ctx.type) {
|
|
2056
|
+
case "move":
|
|
2057
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
2058
|
+
return baseMoveChanges(orig, ctx.changes.rect).rects;
|
|
2059
|
+
case "resize":
|
|
2060
|
+
if (!ctx.changes.rect) return ctx.changes;
|
|
2061
|
+
return baseResizeScaling(orig, ctx.changes.rect, ctx.metadata).rects;
|
|
2062
|
+
case "rotate":
|
|
2063
|
+
return baseRotateChanges(orig, ctx) ?? ctx.changes;
|
|
2064
|
+
case "property-update":
|
|
2065
|
+
if (ctx.changes.rotation !== void 0) {
|
|
2066
|
+
return { ...ctx.changes, ...basePropertyRotationChanges(orig, ctx.changes.rotation) };
|
|
2067
|
+
}
|
|
2068
|
+
return ctx.changes;
|
|
2069
|
+
default:
|
|
2070
|
+
return ctx.changes;
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2074
|
+
__proto__: null,
|
|
2075
|
+
LINE_ENDING_HANDLERS,
|
|
2076
|
+
PatchRegistry,
|
|
2077
|
+
applyInsertUpright,
|
|
2078
|
+
calculateAABBFromVertices,
|
|
2079
|
+
calculateRotatedRectAABB,
|
|
2080
|
+
calculateRotatedRectAABBAroundPoint,
|
|
2081
|
+
calloutVertexConfig,
|
|
2082
|
+
clampAnnotationToPage,
|
|
2083
|
+
compensateRotatedVertexEdit,
|
|
2084
|
+
computeCalloutConnectionPoint,
|
|
2085
|
+
computeCalloutOverallRect,
|
|
2086
|
+
computeRDFromTextBox,
|
|
2087
|
+
computeTextBoxFromRD,
|
|
2088
|
+
createEnding,
|
|
2089
|
+
getRectCenter,
|
|
2090
|
+
lineRectWithEndings,
|
|
2091
|
+
patchCalloutFreeText,
|
|
2092
|
+
patchCircle,
|
|
2093
|
+
patchFreeText,
|
|
2094
|
+
patchInk,
|
|
2095
|
+
patchLine,
|
|
2096
|
+
patchPolygon,
|
|
2097
|
+
patchPolyline,
|
|
2098
|
+
patchRegistry,
|
|
2099
|
+
patchSquare,
|
|
2100
|
+
patchStamp,
|
|
2101
|
+
resolveAnnotationRotationCenter,
|
|
2102
|
+
resolveRotateRects,
|
|
2103
|
+
resolveVertexEditRects,
|
|
2104
|
+
rotatePointAroundCenter: rotatePointAround,
|
|
2105
|
+
rotateVertices
|
|
2106
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
2107
|
+
const COMMENT_SIZE = 24;
|
|
2108
|
+
const textHandlerFactory = {
|
|
2109
|
+
annotationType: PdfAnnotationSubtype.TEXT,
|
|
2110
|
+
create(context) {
|
|
2111
|
+
const { onCommit, getTool, pageSize } = context;
|
|
2112
|
+
return {
|
|
2113
|
+
onPointerDown: (pos) => {
|
|
2114
|
+
const tool = getTool();
|
|
2115
|
+
if (!tool) return;
|
|
2116
|
+
const rect = {
|
|
2117
|
+
origin: { x: pos.x - COMMENT_SIZE / 2, y: pos.y - COMMENT_SIZE / 2 },
|
|
2118
|
+
size: { width: COMMENT_SIZE, height: COMMENT_SIZE }
|
|
2119
|
+
};
|
|
2120
|
+
let anno = {
|
|
2121
|
+
...tool.defaults,
|
|
2122
|
+
rect,
|
|
2123
|
+
type: PdfAnnotationSubtype.TEXT,
|
|
2124
|
+
name: tool.defaults.name ?? PdfAnnotationName.Comment,
|
|
2125
|
+
contents: tool.defaults.contents ?? "",
|
|
2126
|
+
flags: tool.defaults.flags ?? ["print", "noRotate", "noZoom"],
|
|
2127
|
+
pageIndex: context.pageIndex,
|
|
2128
|
+
id: uuidV4(),
|
|
2129
|
+
created: /* @__PURE__ */ new Date()
|
|
2130
|
+
};
|
|
2131
|
+
anno = clampAnnotationToPage(anno, pageSize);
|
|
2132
|
+
onCommit(anno);
|
|
2133
|
+
}
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
};
|
|
2137
|
+
function useClickDetector({
|
|
2138
|
+
threshold = 5,
|
|
2139
|
+
getTool,
|
|
2140
|
+
onClickDetected
|
|
2141
|
+
}) {
|
|
2142
|
+
const [getStartPos, setStartPos] = useState(null);
|
|
2143
|
+
const [getHasMoved, setHasMoved] = useState(false);
|
|
2144
|
+
return {
|
|
2145
|
+
onStart: (pos) => {
|
|
2146
|
+
setStartPos(pos);
|
|
2147
|
+
setHasMoved(false);
|
|
2148
|
+
},
|
|
2149
|
+
onMove: (pos) => {
|
|
2150
|
+
const start = getStartPos();
|
|
2151
|
+
if (!start || getHasMoved()) return;
|
|
2152
|
+
const distance2 = Math.sqrt(Math.pow(pos.x - start.x, 2) + Math.pow(pos.y - start.y, 2));
|
|
2153
|
+
if (distance2 > threshold) {
|
|
2154
|
+
setHasMoved(true);
|
|
2155
|
+
}
|
|
2156
|
+
},
|
|
2157
|
+
onEnd: (pos) => {
|
|
2158
|
+
var _a;
|
|
2159
|
+
const start = getStartPos();
|
|
2160
|
+
if (start && !getHasMoved()) {
|
|
2161
|
+
const tool = getTool();
|
|
2162
|
+
if (tool && "clickBehavior" in tool && ((_a = tool.clickBehavior) == null ? void 0 : _a.enabled)) {
|
|
2163
|
+
onClickDetected(pos, tool);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
setStartPos(null);
|
|
2167
|
+
setHasMoved(false);
|
|
2168
|
+
},
|
|
2169
|
+
hasMoved: getHasMoved,
|
|
2170
|
+
reset: () => {
|
|
2171
|
+
setStartPos(null);
|
|
2172
|
+
setHasMoved(false);
|
|
2173
|
+
}
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
2176
|
+
const freeTextHandlerFactory = {
|
|
2177
|
+
annotationType: PdfAnnotationSubtype.FREETEXT,
|
|
2178
|
+
create(context) {
|
|
2179
|
+
const { onCommit, onPreview, getTool, pageSize, pageIndex, pageRotation } = context;
|
|
2180
|
+
const [getStart, setStart] = useState(null);
|
|
2181
|
+
const clampToPage = (pos) => ({
|
|
2182
|
+
x: clamp(pos.x, 0, pageSize.width),
|
|
2183
|
+
y: clamp(pos.y, 0, pageSize.height)
|
|
2184
|
+
});
|
|
2185
|
+
const getDefaults = () => {
|
|
2186
|
+
const tool = getTool();
|
|
2187
|
+
if (!tool) return null;
|
|
2188
|
+
return {
|
|
2189
|
+
...tool.defaults,
|
|
2190
|
+
fontColor: tool.defaults.fontColor ?? "#000000",
|
|
2191
|
+
opacity: tool.defaults.opacity ?? 1,
|
|
2192
|
+
fontSize: tool.defaults.fontSize ?? 12,
|
|
2193
|
+
fontFamily: tool.defaults.fontFamily ?? PdfStandardFont.Helvetica,
|
|
2194
|
+
color: tool.defaults.color ?? tool.defaults.backgroundColor ?? "transparent",
|
|
2195
|
+
textAlign: tool.defaults.textAlign ?? PdfTextAlignment.Left,
|
|
2196
|
+
verticalAlign: tool.defaults.verticalAlign ?? PdfVerticalAlignment.Top,
|
|
2197
|
+
contents: tool.defaults.contents ?? "Insert text here",
|
|
2198
|
+
flags: tool.defaults.flags ?? ["print"]
|
|
2199
|
+
};
|
|
2200
|
+
};
|
|
2074
2201
|
const clickDetector = useClickDetector({
|
|
2075
2202
|
threshold: 5,
|
|
2076
2203
|
getTool,
|
|
2077
2204
|
onClickDetected: (pos, tool) => {
|
|
2205
|
+
var _a;
|
|
2078
2206
|
const defaults = getDefaults();
|
|
2079
2207
|
if (!defaults) return;
|
|
2080
2208
|
const clickConfig = tool.clickBehavior;
|
|
2081
2209
|
if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
|
|
2082
2210
|
const { width, height } = clickConfig.defaultSize;
|
|
2083
|
-
const halfWidth = width / 2;
|
|
2084
|
-
const halfHeight = height / 2;
|
|
2085
|
-
const x = clamp(pos.x - halfWidth, 0, pageSize.width - width);
|
|
2086
|
-
const y = clamp(pos.y - halfHeight, 0, pageSize.height - height);
|
|
2087
|
-
const strokeWidth = defaults.strokeWidth;
|
|
2088
|
-
const intensity = defaults.cloudyBorderIntensity ?? 0;
|
|
2089
|
-
const pad = intensity > 0 ? getCloudyBorderExtent(intensity, strokeWidth, false) : strokeWidth / 2;
|
|
2090
2211
|
const rect = {
|
|
2091
|
-
origin: { x: x -
|
|
2092
|
-
size: { width
|
|
2212
|
+
origin: { x: pos.x - width / 2, y: pos.y - height / 2 },
|
|
2213
|
+
size: { width, height }
|
|
2093
2214
|
};
|
|
2094
|
-
const
|
|
2215
|
+
const contents = clickConfig.defaultContent ?? defaults.contents;
|
|
2216
|
+
let anno = {
|
|
2095
2217
|
...defaults,
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
id: uuidV4(),
|
|
2099
|
-
pageIndex,
|
|
2218
|
+
contents,
|
|
2219
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
2100
2220
|
rect,
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2221
|
+
pageIndex,
|
|
2222
|
+
id: uuidV4(),
|
|
2223
|
+
created: /* @__PURE__ */ new Date()
|
|
2104
2224
|
};
|
|
2225
|
+
if ((_a = tool.behavior) == null ? void 0 : _a.insertUpright) {
|
|
2226
|
+
anno = applyInsertUpright(anno, pageRotation, false);
|
|
2227
|
+
}
|
|
2228
|
+
anno = clampAnnotationToPage(anno, pageSize);
|
|
2105
2229
|
onCommit(anno);
|
|
2106
2230
|
}
|
|
2107
2231
|
});
|
|
2108
2232
|
const getPreview = (current) => {
|
|
2109
|
-
const
|
|
2110
|
-
if (!
|
|
2111
|
-
const minX = Math.min(p1.x, current.x);
|
|
2112
|
-
const minY = Math.min(p1.y, current.y);
|
|
2113
|
-
const width = Math.abs(p1.x - current.x);
|
|
2114
|
-
const height = Math.abs(p1.y - current.y);
|
|
2233
|
+
const start = getStart();
|
|
2234
|
+
if (!start) return null;
|
|
2115
2235
|
const defaults = getDefaults();
|
|
2116
2236
|
if (!defaults) return null;
|
|
2117
|
-
const
|
|
2118
|
-
const
|
|
2119
|
-
const
|
|
2237
|
+
const minX = Math.min(start.x, current.x);
|
|
2238
|
+
const minY = Math.min(start.y, current.y);
|
|
2239
|
+
const width = Math.abs(start.x - current.x);
|
|
2240
|
+
const height = Math.abs(start.y - current.y);
|
|
2120
2241
|
const rect = {
|
|
2121
|
-
origin: { x: minX
|
|
2122
|
-
size: { width
|
|
2242
|
+
origin: { x: minX, y: minY },
|
|
2243
|
+
size: { width, height }
|
|
2123
2244
|
};
|
|
2124
2245
|
return {
|
|
2125
|
-
type: PdfAnnotationSubtype.
|
|
2246
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
2126
2247
|
bounds: rect,
|
|
2127
2248
|
data: {
|
|
2128
|
-
rect,
|
|
2129
2249
|
...defaults,
|
|
2130
|
-
|
|
2131
|
-
rectangleDifferences: { left: pad, top: pad, right: pad, bottom: pad }
|
|
2132
|
-
}
|
|
2250
|
+
rect
|
|
2133
2251
|
}
|
|
2134
2252
|
};
|
|
2135
2253
|
};
|
|
@@ -2150,39 +2268,41 @@ const squareHandlerFactory = {
|
|
|
2150
2268
|
}
|
|
2151
2269
|
},
|
|
2152
2270
|
onPointerUp: (pos, evt) => {
|
|
2153
|
-
var _a;
|
|
2154
|
-
const
|
|
2155
|
-
if (!
|
|
2271
|
+
var _a, _b;
|
|
2272
|
+
const start = getStart();
|
|
2273
|
+
if (!start) return;
|
|
2156
2274
|
const defaults = getDefaults();
|
|
2157
2275
|
if (!defaults) return;
|
|
2158
2276
|
const clampedPos = clampToPage(pos);
|
|
2159
2277
|
if (!clickDetector.hasMoved()) {
|
|
2160
2278
|
clickDetector.onEnd(clampedPos);
|
|
2161
2279
|
} else {
|
|
2162
|
-
const
|
|
2163
|
-
|
|
2164
|
-
const
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2280
|
+
const minX = Math.min(start.x, clampedPos.x);
|
|
2281
|
+
const minY = Math.min(start.y, clampedPos.y);
|
|
2282
|
+
const width = Math.abs(start.x - clampedPos.x);
|
|
2283
|
+
const height = Math.abs(start.y - clampedPos.y);
|
|
2284
|
+
const rect = {
|
|
2285
|
+
origin: { x: minX, y: minY },
|
|
2286
|
+
size: { width, height }
|
|
2287
|
+
};
|
|
2288
|
+
const tool = getTool();
|
|
2289
|
+
let anno = {
|
|
2290
|
+
...defaults,
|
|
2291
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
2292
|
+
rect,
|
|
2293
|
+
pageIndex: context.pageIndex,
|
|
2294
|
+
id: uuidV4(),
|
|
2295
|
+
created: /* @__PURE__ */ new Date()
|
|
2296
|
+
};
|
|
2297
|
+
if ((_a = tool == null ? void 0 : tool.behavior) == null ? void 0 : _a.insertUpright) {
|
|
2298
|
+
anno = applyInsertUpright(anno, pageRotation, true);
|
|
2180
2299
|
}
|
|
2300
|
+
onCommit(anno);
|
|
2181
2301
|
}
|
|
2182
2302
|
setStart(null);
|
|
2183
2303
|
onPreview(null);
|
|
2184
2304
|
clickDetector.reset();
|
|
2185
|
-
(
|
|
2305
|
+
(_b = evt.releasePointerCapture) == null ? void 0 : _b.call(evt);
|
|
2186
2306
|
},
|
|
2187
2307
|
onPointerLeave: (_, evt) => {
|
|
2188
2308
|
var _a;
|
|
@@ -2201,131 +2321,234 @@ const squareHandlerFactory = {
|
|
|
2201
2321
|
};
|
|
2202
2322
|
}
|
|
2203
2323
|
};
|
|
2204
|
-
const
|
|
2205
|
-
const
|
|
2206
|
-
|
|
2324
|
+
const CLICK_THRESHOLD = 5;
|
|
2325
|
+
const DEFAULT_TB_WIDTH = 150;
|
|
2326
|
+
const DEFAULT_TB_HEIGHT = 40;
|
|
2327
|
+
const calloutFreeTextHandlerFactory = {
|
|
2328
|
+
annotationType: PdfAnnotationSubtype.FREETEXT,
|
|
2207
2329
|
create(context) {
|
|
2208
|
-
const {
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
const
|
|
2212
|
-
|
|
2330
|
+
const { onCommit, onPreview, getTool, pageSize, pageIndex } = context;
|
|
2331
|
+
const [getPhase, setPhase] = useState("arrow");
|
|
2332
|
+
const [getArrowTip, setArrowTip] = useState(null);
|
|
2333
|
+
const [getKnee, setKnee] = useState(null);
|
|
2334
|
+
const [getDownPos, setDownPos] = useState(null);
|
|
2335
|
+
const [getTextBoxStart, setTextBoxStart] = useState(null);
|
|
2336
|
+
const [getDragging, setDragging] = useState(false);
|
|
2337
|
+
const clampToPage = (pos) => ({
|
|
2338
|
+
x: clamp(pos.x, 0, pageSize.width),
|
|
2339
|
+
y: clamp(pos.y, 0, pageSize.height)
|
|
2340
|
+
});
|
|
2341
|
+
const clampTextBox = (tb) => ({
|
|
2342
|
+
origin: {
|
|
2343
|
+
x: clamp(tb.origin.x, 0, pageSize.width - tb.size.width),
|
|
2344
|
+
y: clamp(tb.origin.y, 0, pageSize.height - tb.size.height)
|
|
2345
|
+
},
|
|
2346
|
+
size: tb.size
|
|
2347
|
+
});
|
|
2348
|
+
const getDefaults = () => {
|
|
2213
2349
|
const tool = getTool();
|
|
2214
|
-
if (!tool) return;
|
|
2215
|
-
|
|
2216
|
-
origin: { x: pos.x - width / 2, y: pos.y - height / 2 },
|
|
2217
|
-
size: { width, height }
|
|
2218
|
-
};
|
|
2219
|
-
let anno = {
|
|
2350
|
+
if (!tool) return null;
|
|
2351
|
+
return {
|
|
2220
2352
|
...tool.defaults,
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2353
|
+
fontColor: tool.defaults.fontColor ?? "#000000",
|
|
2354
|
+
opacity: tool.defaults.opacity ?? 1,
|
|
2355
|
+
fontSize: tool.defaults.fontSize ?? 12,
|
|
2356
|
+
fontFamily: tool.defaults.fontFamily ?? PdfStandardFont.Helvetica,
|
|
2357
|
+
color: tool.defaults.color ?? tool.defaults.backgroundColor ?? "transparent",
|
|
2358
|
+
textAlign: tool.defaults.textAlign ?? PdfTextAlignment.Left,
|
|
2359
|
+
verticalAlign: tool.defaults.verticalAlign ?? PdfVerticalAlignment.Top,
|
|
2360
|
+
contents: tool.defaults.contents ?? "Insert text",
|
|
2225
2361
|
flags: tool.defaults.flags ?? ["print"],
|
|
2226
|
-
|
|
2362
|
+
lineEnding: tool.defaults.lineEnding ?? PdfAnnotationLineEnding.OpenArrow,
|
|
2363
|
+
strokeColor: tool.defaults.strokeColor ?? "#000000",
|
|
2364
|
+
strokeWidth: tool.defaults.strokeWidth ?? 1
|
|
2365
|
+
};
|
|
2366
|
+
};
|
|
2367
|
+
const isClick = (a, b) => Math.abs(a.x - b.x) < CLICK_THRESHOLD && Math.abs(a.y - b.y) < CLICK_THRESHOLD;
|
|
2368
|
+
const buildPreview = (cursor) => {
|
|
2369
|
+
const defaults = getDefaults();
|
|
2370
|
+
if (!defaults) return null;
|
|
2371
|
+
const arrowTip = getArrowTip();
|
|
2372
|
+
const knee = getKnee();
|
|
2373
|
+
const phase = getPhase();
|
|
2374
|
+
if (phase === "knee" && arrowTip) {
|
|
2375
|
+
const calloutLine = [arrowTip, cursor];
|
|
2376
|
+
const minX = Math.min(arrowTip.x, cursor.x);
|
|
2377
|
+
const minY = Math.min(arrowTip.y, cursor.y);
|
|
2378
|
+
const w = Math.abs(arrowTip.x - cursor.x);
|
|
2379
|
+
const h = Math.abs(arrowTip.y - cursor.y);
|
|
2380
|
+
const bounds = {
|
|
2381
|
+
origin: { x: minX, y: minY },
|
|
2382
|
+
size: { width: Math.max(w, 1), height: Math.max(h, 1) }
|
|
2383
|
+
};
|
|
2384
|
+
return {
|
|
2385
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
2386
|
+
bounds,
|
|
2387
|
+
data: {
|
|
2388
|
+
...defaults,
|
|
2389
|
+
rect: bounds,
|
|
2390
|
+
calloutLine
|
|
2391
|
+
}
|
|
2392
|
+
};
|
|
2393
|
+
}
|
|
2394
|
+
if (phase === "textbox" && arrowTip && knee) {
|
|
2395
|
+
const tbStart = getTextBoxStart();
|
|
2396
|
+
let textBox;
|
|
2397
|
+
if (getDragging() && tbStart) {
|
|
2398
|
+
textBox = {
|
|
2399
|
+
origin: { x: Math.min(tbStart.x, cursor.x), y: Math.min(tbStart.y, cursor.y) },
|
|
2400
|
+
size: {
|
|
2401
|
+
width: Math.max(Math.abs(cursor.x - tbStart.x), 20),
|
|
2402
|
+
height: Math.max(Math.abs(cursor.y - tbStart.y), 14)
|
|
2403
|
+
}
|
|
2404
|
+
};
|
|
2405
|
+
} else {
|
|
2406
|
+
textBox = {
|
|
2407
|
+
origin: { x: cursor.x - DEFAULT_TB_WIDTH / 2, y: cursor.y - DEFAULT_TB_HEIGHT / 2 },
|
|
2408
|
+
size: { width: DEFAULT_TB_WIDTH, height: DEFAULT_TB_HEIGHT }
|
|
2409
|
+
};
|
|
2410
|
+
}
|
|
2411
|
+
textBox = clampTextBox(textBox);
|
|
2412
|
+
const connectionPoint = computeCalloutConnectionPoint(knee, textBox);
|
|
2413
|
+
const calloutLine = [arrowTip, knee, connectionPoint];
|
|
2414
|
+
const overallRect = computeCalloutOverallRect(
|
|
2415
|
+
textBox,
|
|
2416
|
+
calloutLine,
|
|
2417
|
+
defaults.lineEnding,
|
|
2418
|
+
defaults.strokeWidth
|
|
2419
|
+
);
|
|
2420
|
+
return {
|
|
2421
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
2422
|
+
bounds: overallRect,
|
|
2423
|
+
data: {
|
|
2424
|
+
...defaults,
|
|
2425
|
+
rect: overallRect,
|
|
2426
|
+
calloutLine,
|
|
2427
|
+
textBox
|
|
2428
|
+
}
|
|
2429
|
+
};
|
|
2430
|
+
}
|
|
2431
|
+
return null;
|
|
2432
|
+
};
|
|
2433
|
+
const commitCallout = (tb) => {
|
|
2434
|
+
const defaults = getDefaults();
|
|
2435
|
+
const arrowTip = getArrowTip();
|
|
2436
|
+
const knee = getKnee();
|
|
2437
|
+
if (!defaults || !arrowTip || !knee) return;
|
|
2438
|
+
const textBox = clampTextBox(tb);
|
|
2439
|
+
const connectionPoint = computeCalloutConnectionPoint(knee, textBox);
|
|
2440
|
+
const calloutLine = [arrowTip, knee, connectionPoint];
|
|
2441
|
+
const overallRect = computeCalloutOverallRect(
|
|
2442
|
+
textBox,
|
|
2443
|
+
calloutLine,
|
|
2444
|
+
defaults.lineEnding,
|
|
2445
|
+
defaults.strokeWidth
|
|
2446
|
+
);
|
|
2447
|
+
const rd = computeRDFromTextBox(overallRect, textBox);
|
|
2448
|
+
const anno = {
|
|
2449
|
+
...defaults,
|
|
2450
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
2451
|
+
intent: "FreeTextCallout",
|
|
2452
|
+
rect: overallRect,
|
|
2453
|
+
rectangleDifferences: rd,
|
|
2454
|
+
calloutLine,
|
|
2455
|
+
pageIndex,
|
|
2227
2456
|
id: uuidV4(),
|
|
2228
2457
|
created: /* @__PURE__ */ new Date()
|
|
2229
2458
|
};
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
}
|
|
2233
|
-
anno = clampAnnotationToPage(anno, pageSize);
|
|
2234
|
-
onCommit(anno, ctx);
|
|
2459
|
+
onCommit(anno);
|
|
2460
|
+
resetState();
|
|
2235
2461
|
};
|
|
2236
|
-
const
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2462
|
+
const resetState = () => {
|
|
2463
|
+
setPhase("arrow");
|
|
2464
|
+
setArrowTip(null);
|
|
2465
|
+
setKnee(null);
|
|
2466
|
+
setDownPos(null);
|
|
2467
|
+
setTextBoxStart(null);
|
|
2468
|
+
setDragging(false);
|
|
2469
|
+
onPreview(null);
|
|
2244
2470
|
};
|
|
2245
2471
|
return {
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
const
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
return {
|
|
2258
|
-
buffer,
|
|
2259
|
-
width: (imageSize == null ? void 0 : imageSize.width) ?? fitted.width,
|
|
2260
|
-
height: (imageSize == null ? void 0 : imageSize.height) ?? fitted.height
|
|
2261
|
-
};
|
|
2262
|
-
}).catch(() => null);
|
|
2263
|
-
entry = { promise, refs: 1 };
|
|
2264
|
-
imageFetchCache.set(imageSrc, entry);
|
|
2265
|
-
} else {
|
|
2266
|
-
entry.refs++;
|
|
2267
|
-
}
|
|
2268
|
-
entry.promise.then((result) => {
|
|
2269
|
-
if (!result) return;
|
|
2270
|
-
cachedBuffer = result.buffer;
|
|
2271
|
-
cachedSize = { width: result.width, height: result.height };
|
|
2272
|
-
});
|
|
2273
|
-
},
|
|
2274
|
-
onHandlerActiveEnd: () => {
|
|
2275
|
-
const tool = getTool();
|
|
2276
|
-
const imageSrc = tool == null ? void 0 : tool.defaults.imageSrc;
|
|
2277
|
-
if (imageSrc) {
|
|
2278
|
-
const entry = imageFetchCache.get(imageSrc);
|
|
2279
|
-
if (entry && --entry.refs <= 0) {
|
|
2280
|
-
imageFetchCache.delete(imageSrc);
|
|
2281
|
-
}
|
|
2472
|
+
onPointerDown: (pos, evt) => {
|
|
2473
|
+
var _a, _b;
|
|
2474
|
+
const clampedPos = clampToPage(pos);
|
|
2475
|
+
const phase = getPhase();
|
|
2476
|
+
if (phase === "arrow" || phase === "knee") {
|
|
2477
|
+
setDownPos(clampedPos);
|
|
2478
|
+
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
2479
|
+
} else if (phase === "textbox") {
|
|
2480
|
+
setTextBoxStart(clampedPos);
|
|
2481
|
+
setDragging(true);
|
|
2482
|
+
(_b = evt.setPointerCapture) == null ? void 0 : _b.call(evt);
|
|
2282
2483
|
}
|
|
2283
|
-
cachedBuffer = null;
|
|
2284
|
-
cachedSize = null;
|
|
2285
|
-
onPreview(null);
|
|
2286
2484
|
},
|
|
2287
2485
|
onPointerMove: (pos) => {
|
|
2288
|
-
|
|
2289
|
-
const
|
|
2290
|
-
if (
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
}
|
|
2295
|
-
onPreview({
|
|
2296
|
-
type: PdfAnnotationSubtype.STAMP,
|
|
2297
|
-
bounds: rect,
|
|
2298
|
-
data: { rect, ghostUrl: tool.defaults.imageSrc, pageRotation }
|
|
2299
|
-
});
|
|
2486
|
+
const clampedPos = clampToPage(pos);
|
|
2487
|
+
const phase = getPhase();
|
|
2488
|
+
if (phase === "textbox" && getDragging()) {
|
|
2489
|
+
onPreview(buildPreview(clampedPos));
|
|
2490
|
+
} else if (phase === "knee" || phase === "textbox") {
|
|
2491
|
+
onPreview(buildPreview(clampedPos));
|
|
2492
|
+
}
|
|
2300
2493
|
},
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
const
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
}
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2494
|
+
onPointerUp: (pos, evt) => {
|
|
2495
|
+
var _a, _b, _c, _d;
|
|
2496
|
+
const clampedPos = clampToPage(pos);
|
|
2497
|
+
const phase = getPhase();
|
|
2498
|
+
const downPos = getDownPos();
|
|
2499
|
+
if (phase === "arrow" && downPos && isClick(downPos, clampedPos)) {
|
|
2500
|
+
setArrowTip(clampedPos);
|
|
2501
|
+
setPhase("knee");
|
|
2502
|
+
setDownPos(null);
|
|
2503
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
2504
|
+
return;
|
|
2505
|
+
}
|
|
2506
|
+
if (phase === "knee" && downPos && isClick(downPos, clampedPos)) {
|
|
2507
|
+
setKnee(clampedPos);
|
|
2508
|
+
setPhase("textbox");
|
|
2509
|
+
setDownPos(null);
|
|
2510
|
+
(_b = evt.releasePointerCapture) == null ? void 0 : _b.call(evt);
|
|
2511
|
+
return;
|
|
2512
|
+
}
|
|
2513
|
+
if (phase === "textbox" && getDragging()) {
|
|
2514
|
+
const tbStart = getTextBoxStart();
|
|
2515
|
+
if (tbStart) {
|
|
2516
|
+
const minX = Math.min(tbStart.x, clampedPos.x);
|
|
2517
|
+
const minY = Math.min(tbStart.y, clampedPos.y);
|
|
2518
|
+
const w = Math.abs(clampedPos.x - tbStart.x);
|
|
2519
|
+
const h = Math.abs(clampedPos.y - tbStart.y);
|
|
2520
|
+
if (w > 5 || h > 5) {
|
|
2521
|
+
const textBox = {
|
|
2522
|
+
origin: { x: minX, y: minY },
|
|
2523
|
+
size: { width: Math.max(w, 20), height: Math.max(h, 14) }
|
|
2524
|
+
};
|
|
2525
|
+
commitCallout(textBox);
|
|
2526
|
+
} else {
|
|
2527
|
+
commitCallout({
|
|
2528
|
+
origin: {
|
|
2529
|
+
x: tbStart.x - DEFAULT_TB_WIDTH / 2,
|
|
2530
|
+
y: tbStart.y - DEFAULT_TB_HEIGHT / 2
|
|
2531
|
+
},
|
|
2532
|
+
size: { width: DEFAULT_TB_WIDTH, height: DEFAULT_TB_HEIGHT }
|
|
2533
|
+
});
|
|
2317
2534
|
}
|
|
2318
|
-
}
|
|
2535
|
+
}
|
|
2536
|
+
(_c = evt.releasePointerCapture) == null ? void 0 : _c.call(evt);
|
|
2537
|
+
return;
|
|
2319
2538
|
}
|
|
2539
|
+
setDownPos(null);
|
|
2540
|
+
(_d = evt.releasePointerCapture) == null ? void 0 : _d.call(evt);
|
|
2320
2541
|
},
|
|
2321
|
-
|
|
2322
|
-
|
|
2542
|
+
onPointerCancel: (_, evt) => {
|
|
2543
|
+
var _a;
|
|
2544
|
+
resetState();
|
|
2545
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
2323
2546
|
}
|
|
2324
2547
|
};
|
|
2325
2548
|
}
|
|
2326
2549
|
};
|
|
2327
|
-
const
|
|
2328
|
-
annotationType: PdfAnnotationSubtype.
|
|
2550
|
+
const lineHandlerFactory = {
|
|
2551
|
+
annotationType: PdfAnnotationSubtype.LINE,
|
|
2329
2552
|
create(context) {
|
|
2330
2553
|
const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
|
|
2331
2554
|
const [getStart, setStart] = useState(null);
|
|
@@ -2338,12 +2561,16 @@ const circleHandlerFactory = {
|
|
|
2338
2561
|
if (!tool) return null;
|
|
2339
2562
|
return {
|
|
2340
2563
|
...tool.defaults,
|
|
2341
|
-
strokeWidth: tool.defaults.strokeWidth ??
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2564
|
+
strokeWidth: tool.defaults.strokeWidth ?? 1,
|
|
2565
|
+
lineEndings: tool.defaults.lineEndings ?? {
|
|
2566
|
+
start: PdfAnnotationLineEnding.None,
|
|
2567
|
+
end: PdfAnnotationLineEnding.None
|
|
2568
|
+
},
|
|
2345
2569
|
color: tool.defaults.color ?? "#000000",
|
|
2346
2570
|
opacity: tool.defaults.opacity ?? 1,
|
|
2571
|
+
strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
|
|
2572
|
+
strokeDashArray: tool.defaults.strokeDashArray ?? [],
|
|
2573
|
+
strokeColor: tool.defaults.strokeColor ?? "#000000",
|
|
2347
2574
|
flags: tool.defaults.flags ?? ["print"]
|
|
2348
2575
|
};
|
|
2349
2576
|
};
|
|
@@ -2355,57 +2582,48 @@ const circleHandlerFactory = {
|
|
|
2355
2582
|
if (!defaults) return;
|
|
2356
2583
|
const clickConfig = tool.clickBehavior;
|
|
2357
2584
|
if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
|
|
2358
|
-
const
|
|
2359
|
-
const
|
|
2360
|
-
const
|
|
2361
|
-
const
|
|
2362
|
-
const
|
|
2363
|
-
const
|
|
2364
|
-
const
|
|
2365
|
-
const
|
|
2366
|
-
const
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2585
|
+
const angle = clickConfig.defaultAngle ?? 0;
|
|
2586
|
+
const length = clickConfig.defaultLength;
|
|
2587
|
+
const halfLength = length / 2;
|
|
2588
|
+
const startX = pos.x - halfLength * Math.cos(angle);
|
|
2589
|
+
const startY = pos.y - halfLength * Math.sin(angle);
|
|
2590
|
+
const endX = pos.x + halfLength * Math.cos(angle);
|
|
2591
|
+
const endY = pos.y + halfLength * Math.sin(angle);
|
|
2592
|
+
const start = clampToPage({ x: startX, y: startY });
|
|
2593
|
+
const end = clampToPage({ x: endX, y: endY });
|
|
2594
|
+
const rect = lineRectWithEndings(
|
|
2595
|
+
[start, end],
|
|
2596
|
+
defaults.strokeWidth,
|
|
2597
|
+
defaults.lineEndings
|
|
2598
|
+
);
|
|
2599
|
+
onCommit({
|
|
2371
2600
|
...defaults,
|
|
2372
|
-
type: PdfAnnotationSubtype.CIRCLE,
|
|
2373
|
-
created: /* @__PURE__ */ new Date(),
|
|
2374
|
-
id: uuidV4(),
|
|
2375
|
-
pageIndex,
|
|
2376
2601
|
rect,
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2602
|
+
linePoints: { start, end },
|
|
2603
|
+
pageIndex,
|
|
2604
|
+
id: uuidV4(),
|
|
2605
|
+
created: /* @__PURE__ */ new Date(),
|
|
2606
|
+
type: PdfAnnotationSubtype.LINE
|
|
2607
|
+
});
|
|
2382
2608
|
}
|
|
2383
2609
|
});
|
|
2384
2610
|
const getPreview = (current) => {
|
|
2385
|
-
const
|
|
2386
|
-
if (!
|
|
2387
|
-
const minX = Math.min(p1.x, current.x);
|
|
2388
|
-
const minY = Math.min(p1.y, current.y);
|
|
2389
|
-
const width = Math.abs(p1.x - current.x);
|
|
2390
|
-
const height = Math.abs(p1.y - current.y);
|
|
2611
|
+
const start = getStart();
|
|
2612
|
+
if (!start) return null;
|
|
2391
2613
|
const defaults = getDefaults();
|
|
2392
2614
|
if (!defaults) return null;
|
|
2393
|
-
const
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
size: { width: width + 2 * pad, height: height + 2 * pad }
|
|
2399
|
-
};
|
|
2615
|
+
const bounds = lineRectWithEndings(
|
|
2616
|
+
[start, current],
|
|
2617
|
+
defaults.strokeWidth,
|
|
2618
|
+
defaults.lineEndings
|
|
2619
|
+
);
|
|
2400
2620
|
return {
|
|
2401
|
-
type: PdfAnnotationSubtype.
|
|
2402
|
-
bounds
|
|
2621
|
+
type: PdfAnnotationSubtype.LINE,
|
|
2622
|
+
bounds,
|
|
2403
2623
|
data: {
|
|
2404
|
-
rect,
|
|
2405
2624
|
...defaults,
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
}
|
|
2625
|
+
rect: bounds,
|
|
2626
|
+
linePoints: { start, end: current }
|
|
2409
2627
|
}
|
|
2410
2628
|
};
|
|
2411
2629
|
};
|
|
@@ -2427,33 +2645,30 @@ const circleHandlerFactory = {
|
|
|
2427
2645
|
},
|
|
2428
2646
|
onPointerUp: (pos, evt) => {
|
|
2429
2647
|
var _a;
|
|
2430
|
-
const
|
|
2431
|
-
if (!
|
|
2432
|
-
const defaults = getDefaults();
|
|
2433
|
-
if (!defaults) return;
|
|
2648
|
+
const start = getStart();
|
|
2649
|
+
if (!start) return;
|
|
2434
2650
|
const clampedPos = clampToPage(pos);
|
|
2435
2651
|
if (!clickDetector.hasMoved()) {
|
|
2436
2652
|
clickDetector.onEnd(clampedPos);
|
|
2437
2653
|
} else {
|
|
2438
|
-
const
|
|
2439
|
-
if (!
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2654
|
+
const defaults = getDefaults();
|
|
2655
|
+
if (!defaults) return;
|
|
2656
|
+
if (Math.abs(clampedPos.x - start.x) > 2 || Math.abs(clampedPos.y - start.y) > 2) {
|
|
2657
|
+
const rect = lineRectWithEndings(
|
|
2658
|
+
[start, clampedPos],
|
|
2659
|
+
defaults.strokeWidth,
|
|
2660
|
+
defaults.lineEndings
|
|
2661
|
+
);
|
|
2662
|
+
onCommit({
|
|
2663
|
+
...defaults,
|
|
2664
|
+
rect,
|
|
2665
|
+
linePoints: { start, end: clampedPos },
|
|
2666
|
+
pageIndex,
|
|
2667
|
+
id: uuidV4(),
|
|
2447
2668
|
flags: ["print"],
|
|
2448
2669
|
created: /* @__PURE__ */ new Date(),
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
rect: preview.data.rect,
|
|
2452
|
-
...pad !== void 0 && {
|
|
2453
|
-
rectangleDifferences: { left: pad, top: pad, right: pad, bottom: pad }
|
|
2454
|
-
}
|
|
2455
|
-
};
|
|
2456
|
-
onCommit(anno);
|
|
2670
|
+
type: PdfAnnotationSubtype.LINE
|
|
2671
|
+
});
|
|
2457
2672
|
}
|
|
2458
2673
|
}
|
|
2459
2674
|
setStart(null);
|
|
@@ -2478,11 +2693,12 @@ const circleHandlerFactory = {
|
|
|
2478
2693
|
};
|
|
2479
2694
|
}
|
|
2480
2695
|
};
|
|
2481
|
-
const
|
|
2482
|
-
annotationType: PdfAnnotationSubtype.
|
|
2696
|
+
const polylineHandlerFactory = {
|
|
2697
|
+
annotationType: PdfAnnotationSubtype.POLYLINE,
|
|
2483
2698
|
create(context) {
|
|
2484
|
-
const {
|
|
2485
|
-
const [
|
|
2699
|
+
const { onCommit, onPreview, getTool, pageSize } = context;
|
|
2700
|
+
const [getVertices, setVertices] = useState([]);
|
|
2701
|
+
const [getCurrent, setCurrent] = useState(null);
|
|
2486
2702
|
const clampToPage = (pos) => ({
|
|
2487
2703
|
x: clamp(pos.x, 0, pageSize.width),
|
|
2488
2704
|
y: clamp(pos.y, 0, pageSize.height)
|
|
@@ -2492,708 +2708,909 @@ const linkHandlerFactory = {
|
|
|
2492
2708
|
if (!tool) return null;
|
|
2493
2709
|
return {
|
|
2494
2710
|
...tool.defaults,
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2711
|
+
strokeWidth: tool.defaults.strokeWidth ?? 1,
|
|
2712
|
+
lineEndings: tool.defaults.lineEndings ?? {
|
|
2713
|
+
start: PdfAnnotationLineEnding.None,
|
|
2714
|
+
end: PdfAnnotationLineEnding.None
|
|
2715
|
+
},
|
|
2716
|
+
color: tool.defaults.color ?? "#000000",
|
|
2717
|
+
opacity: tool.defaults.opacity ?? 1,
|
|
2718
|
+
strokeColor: tool.defaults.strokeColor ?? "#000000",
|
|
2719
|
+
strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
|
|
2720
|
+
strokeDashArray: tool.defaults.strokeDashArray ?? [],
|
|
2721
|
+
flags: tool.defaults.flags ?? ["print"]
|
|
2500
2722
|
};
|
|
2501
2723
|
};
|
|
2502
|
-
const
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
onClickDetected: (pos, tool) => {
|
|
2506
|
-
const defaults = getDefaults();
|
|
2507
|
-
if (!defaults) return;
|
|
2508
|
-
const clickConfig = tool.clickBehavior;
|
|
2509
|
-
if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
|
|
2510
|
-
const { width, height } = clickConfig.defaultSize;
|
|
2511
|
-
const halfWidth = width / 2;
|
|
2512
|
-
const halfHeight = height / 2;
|
|
2513
|
-
const x = clamp(pos.x - halfWidth, 0, pageSize.width - width);
|
|
2514
|
-
const y = clamp(pos.y - halfHeight, 0, pageSize.height - height);
|
|
2515
|
-
const rect = {
|
|
2516
|
-
origin: { x, y },
|
|
2517
|
-
size: { width, height }
|
|
2518
|
-
};
|
|
2519
|
-
const anno = {
|
|
2520
|
-
...defaults,
|
|
2521
|
-
type: PdfAnnotationSubtype.LINK,
|
|
2522
|
-
target: void 0,
|
|
2523
|
-
created: /* @__PURE__ */ new Date(),
|
|
2524
|
-
id: uuidV4(),
|
|
2525
|
-
pageIndex,
|
|
2526
|
-
rect
|
|
2527
|
-
};
|
|
2528
|
-
onCommit(anno);
|
|
2529
|
-
}
|
|
2530
|
-
});
|
|
2531
|
-
const getPreview = (current) => {
|
|
2532
|
-
const p1 = getStart();
|
|
2533
|
-
if (!p1) return null;
|
|
2534
|
-
const minX = Math.min(p1.x, current.x);
|
|
2535
|
-
const minY = Math.min(p1.y, current.y);
|
|
2536
|
-
const width = Math.abs(p1.x - current.x);
|
|
2537
|
-
const height = Math.abs(p1.y - current.y);
|
|
2724
|
+
const commitPolyline = () => {
|
|
2725
|
+
const vertices = getVertices();
|
|
2726
|
+
if (vertices.length < 2) return;
|
|
2538
2727
|
const defaults = getDefaults();
|
|
2539
|
-
if (!defaults) return
|
|
2540
|
-
const rect =
|
|
2541
|
-
|
|
2542
|
-
|
|
2728
|
+
if (!defaults) return;
|
|
2729
|
+
const rect = lineRectWithEndings(
|
|
2730
|
+
vertices,
|
|
2731
|
+
defaults.strokeWidth,
|
|
2732
|
+
defaults.lineEndings
|
|
2733
|
+
);
|
|
2734
|
+
const anno = {
|
|
2735
|
+
...defaults,
|
|
2736
|
+
vertices,
|
|
2737
|
+
rect,
|
|
2738
|
+
type: PdfAnnotationSubtype.POLYLINE,
|
|
2739
|
+
pageIndex: context.pageIndex,
|
|
2740
|
+
id: uuidV4(),
|
|
2741
|
+
created: /* @__PURE__ */ new Date()
|
|
2543
2742
|
};
|
|
2743
|
+
onCommit(anno);
|
|
2744
|
+
setVertices([]);
|
|
2745
|
+
setCurrent(null);
|
|
2746
|
+
onPreview(null);
|
|
2747
|
+
};
|
|
2748
|
+
const getPreview = () => {
|
|
2749
|
+
const vertices = getVertices();
|
|
2750
|
+
const currentPos = getCurrent();
|
|
2751
|
+
if (vertices.length === 0 || !currentPos) return null;
|
|
2752
|
+
const defaults = getDefaults();
|
|
2753
|
+
if (!defaults) return null;
|
|
2754
|
+
const allPoints = [...vertices, currentPos];
|
|
2755
|
+
const bounds = lineRectWithEndings(
|
|
2756
|
+
allPoints,
|
|
2757
|
+
defaults.strokeWidth,
|
|
2758
|
+
defaults.lineEndings
|
|
2759
|
+
);
|
|
2544
2760
|
return {
|
|
2545
|
-
type: PdfAnnotationSubtype.
|
|
2546
|
-
bounds
|
|
2761
|
+
type: PdfAnnotationSubtype.POLYLINE,
|
|
2762
|
+
bounds,
|
|
2547
2763
|
data: {
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
strokeDashArray: defaults.strokeDashArray
|
|
2764
|
+
...defaults,
|
|
2765
|
+
rect: bounds,
|
|
2766
|
+
vertices: allPoints,
|
|
2767
|
+
currentVertex: currentPos
|
|
2553
2768
|
}
|
|
2554
2769
|
};
|
|
2555
2770
|
};
|
|
2556
2771
|
return {
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
setStart(clampedPos);
|
|
2561
|
-
clickDetector.onStart(clampedPos);
|
|
2562
|
-
onPreview(getPreview(clampedPos));
|
|
2563
|
-
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
2564
|
-
},
|
|
2565
|
-
onPointerMove: (pos) => {
|
|
2566
|
-
const clampedPos = clampToPage(pos);
|
|
2567
|
-
clickDetector.onMove(clampedPos);
|
|
2568
|
-
if (getStart() && clickDetector.hasMoved()) {
|
|
2569
|
-
onPreview(getPreview(clampedPos));
|
|
2772
|
+
onClick: (pos, evt) => {
|
|
2773
|
+
if (evt.metaKey || evt.ctrlKey) {
|
|
2774
|
+
return;
|
|
2570
2775
|
}
|
|
2571
|
-
},
|
|
2572
|
-
onPointerUp: (pos, evt) => {
|
|
2573
|
-
var _a;
|
|
2574
|
-
const p1 = getStart();
|
|
2575
|
-
if (!p1) return;
|
|
2576
|
-
const defaults = getDefaults();
|
|
2577
|
-
if (!defaults) return;
|
|
2578
2776
|
const clampedPos = clampToPage(pos);
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
if (preview) {
|
|
2584
|
-
const anno = {
|
|
2585
|
-
...defaults,
|
|
2586
|
-
type: PdfAnnotationSubtype.LINK,
|
|
2587
|
-
target: void 0,
|
|
2588
|
-
created: /* @__PURE__ */ new Date(),
|
|
2589
|
-
id: uuidV4(),
|
|
2590
|
-
pageIndex,
|
|
2591
|
-
rect: preview.data.rect
|
|
2592
|
-
};
|
|
2593
|
-
onCommit(anno);
|
|
2594
|
-
}
|
|
2777
|
+
const vertices = getVertices();
|
|
2778
|
+
const lastVertex = vertices[vertices.length - 1];
|
|
2779
|
+
if (lastVertex && Math.abs(lastVertex.x - clampedPos.x) < 1 && Math.abs(lastVertex.y - clampedPos.y) < 1) {
|
|
2780
|
+
return;
|
|
2595
2781
|
}
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
2782
|
+
setVertices([...vertices, clampedPos]);
|
|
2783
|
+
setCurrent(clampedPos);
|
|
2784
|
+
onPreview(getPreview());
|
|
2600
2785
|
},
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
setStart(null);
|
|
2604
|
-
onPreview(null);
|
|
2605
|
-
clickDetector.reset();
|
|
2606
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
2786
|
+
onDoubleClick: () => {
|
|
2787
|
+
commitPolyline();
|
|
2607
2788
|
},
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2789
|
+
onPointerMove: (pos) => {
|
|
2790
|
+
if (getVertices().length > 0) {
|
|
2791
|
+
const clampedPos = clampToPage(pos);
|
|
2792
|
+
setCurrent(clampedPos);
|
|
2793
|
+
onPreview(getPreview());
|
|
2794
|
+
}
|
|
2795
|
+
},
|
|
2796
|
+
onPointerCancel: () => {
|
|
2797
|
+
setVertices([]);
|
|
2798
|
+
setCurrent(null);
|
|
2611
2799
|
onPreview(null);
|
|
2612
|
-
clickDetector.reset();
|
|
2613
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
2614
2800
|
}
|
|
2615
2801
|
};
|
|
2616
2802
|
}
|
|
2617
2803
|
};
|
|
2618
|
-
const
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
...tool.defaults,
|
|
2629
|
-
rect: selection.rect,
|
|
2630
|
-
segmentRects: selection.segmentRects,
|
|
2631
|
-
pageIndex: selection.pageIndex,
|
|
2632
|
-
created: /* @__PURE__ */ new Date(),
|
|
2633
|
-
id,
|
|
2634
|
-
...text != null && { custom: { text } }
|
|
2635
|
-
});
|
|
2636
|
-
if ((_a = tool.behavior) == null ? void 0 : _a.selectAfterCreate) {
|
|
2637
|
-
context.selectAnnotation(selection.pageIndex, id);
|
|
2638
|
-
}
|
|
2639
|
-
});
|
|
2640
|
-
}
|
|
2641
|
-
}
|
|
2642
|
-
};
|
|
2643
|
-
function computeCaretRect(lastSegRect) {
|
|
2644
|
-
const lineHeight = lastSegRect.size.height;
|
|
2645
|
-
const height = lineHeight / 2;
|
|
2646
|
-
const width = height;
|
|
2647
|
-
const lineEndX = lastSegRect.origin.x + lastSegRect.size.width;
|
|
2648
|
-
return {
|
|
2649
|
-
origin: {
|
|
2650
|
-
x: lineEndX - width / 2,
|
|
2651
|
-
y: lastSegRect.origin.y + lineHeight / 2
|
|
2652
|
-
},
|
|
2653
|
-
size: { width, height }
|
|
2654
|
-
};
|
|
2655
|
-
}
|
|
2656
|
-
const insertTextSelectionHandler = {
|
|
2657
|
-
toolId: "insertText",
|
|
2658
|
-
handle(context, selections, getText) {
|
|
2659
|
-
const tool = context.getTool();
|
|
2660
|
-
if (!tool) return;
|
|
2661
|
-
const getDefaults = () => ({
|
|
2662
|
-
strokeColor: tool.defaults.strokeColor ?? "#E44234",
|
|
2663
|
-
opacity: tool.defaults.opacity ?? 1,
|
|
2664
|
-
flags: tool.defaults.flags ?? ["print"]
|
|
2665
|
-
});
|
|
2666
|
-
for (const selection of selections) {
|
|
2667
|
-
const lastSegRect = selection.segmentRects[selection.segmentRects.length - 1];
|
|
2668
|
-
if (!lastSegRect) continue;
|
|
2669
|
-
const caretRect = computeCaretRect(lastSegRect);
|
|
2670
|
-
const caretId = uuidV4();
|
|
2671
|
-
const defaults = getDefaults();
|
|
2672
|
-
getText().then((text) => {
|
|
2673
|
-
var _a;
|
|
2674
|
-
context.createAnnotation(selection.pageIndex, {
|
|
2675
|
-
type: PdfAnnotationSubtype.CARET,
|
|
2676
|
-
id: caretId,
|
|
2677
|
-
pageIndex: selection.pageIndex,
|
|
2678
|
-
rect: caretRect,
|
|
2679
|
-
strokeColor: defaults.strokeColor,
|
|
2680
|
-
opacity: defaults.opacity,
|
|
2681
|
-
intent: "Insert",
|
|
2682
|
-
rectangleDifferences: { left: 0.5, top: 0.5, right: 0.5, bottom: 0.5 },
|
|
2683
|
-
created: /* @__PURE__ */ new Date(),
|
|
2684
|
-
flags: defaults.flags,
|
|
2685
|
-
...text != null && { custom: { text } }
|
|
2686
|
-
});
|
|
2687
|
-
if ((_a = tool.behavior) == null ? void 0 : _a.selectAfterCreate) {
|
|
2688
|
-
context.selectAnnotation(selection.pageIndex, caretId);
|
|
2689
|
-
}
|
|
2690
|
-
});
|
|
2691
|
-
}
|
|
2692
|
-
}
|
|
2693
|
-
};
|
|
2694
|
-
const replaceTextSelectionHandler = {
|
|
2695
|
-
toolId: "replaceText",
|
|
2696
|
-
handle(context, selections, getText) {
|
|
2697
|
-
const tool = context.getTool();
|
|
2698
|
-
if (!tool) return;
|
|
2699
|
-
const getDefaults = () => ({
|
|
2700
|
-
strokeColor: tool.defaults.strokeColor ?? "#E44234",
|
|
2701
|
-
opacity: tool.defaults.opacity ?? 1,
|
|
2702
|
-
flags: tool.defaults.flags ?? ["print"]
|
|
2804
|
+
const HANDLE_SIZE_PX = 14;
|
|
2805
|
+
const polygonHandlerFactory = {
|
|
2806
|
+
annotationType: PdfAnnotationSubtype.POLYGON,
|
|
2807
|
+
create(context) {
|
|
2808
|
+
const { onCommit, onPreview, getTool, scale, pageSize } = context;
|
|
2809
|
+
const [getVertices, setVertices] = useState([]);
|
|
2810
|
+
const [getCurrent, setCurrent] = useState(null);
|
|
2811
|
+
const clampToPage = (pos) => ({
|
|
2812
|
+
x: clamp(pos.x, 0, pageSize.width),
|
|
2813
|
+
y: clamp(pos.y, 0, pageSize.height)
|
|
2703
2814
|
});
|
|
2704
|
-
|
|
2705
|
-
const
|
|
2706
|
-
if (
|
|
2707
|
-
const
|
|
2708
|
-
const
|
|
2709
|
-
const
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
id: caretId,
|
|
2716
|
-
pageIndex: selection.pageIndex,
|
|
2717
|
-
rect: caretRect,
|
|
2718
|
-
strokeColor: defaults.strokeColor,
|
|
2719
|
-
opacity: defaults.opacity,
|
|
2720
|
-
intent: "Replace",
|
|
2721
|
-
rectangleDifferences: { left: 0.5, top: 0.5, right: 0.5, bottom: 0.5 },
|
|
2722
|
-
created: /* @__PURE__ */ new Date(),
|
|
2723
|
-
flags: defaults.flags
|
|
2724
|
-
});
|
|
2725
|
-
context.createAnnotation(selection.pageIndex, {
|
|
2726
|
-
type: PdfAnnotationSubtype.STRIKEOUT,
|
|
2727
|
-
id: strikeoutId,
|
|
2728
|
-
pageIndex: selection.pageIndex,
|
|
2729
|
-
rect: selection.rect,
|
|
2730
|
-
segmentRects: selection.segmentRects,
|
|
2731
|
-
strokeColor: defaults.strokeColor,
|
|
2732
|
-
opacity: defaults.opacity,
|
|
2733
|
-
intent: "StrikeOutTextEdit",
|
|
2734
|
-
inReplyToId: caretId,
|
|
2735
|
-
replyType: PdfAnnotationReplyType.Group,
|
|
2736
|
-
created: /* @__PURE__ */ new Date(),
|
|
2737
|
-
flags: defaults.flags,
|
|
2738
|
-
...text != null && { custom: { text } }
|
|
2739
|
-
});
|
|
2740
|
-
if ((_a = tool.behavior) == null ? void 0 : _a.selectAfterCreate) {
|
|
2741
|
-
context.selectAnnotation(selection.pageIndex, caretId);
|
|
2742
|
-
}
|
|
2743
|
-
});
|
|
2744
|
-
}
|
|
2745
|
-
}
|
|
2746
|
-
};
|
|
2747
|
-
const patchInk = (original, ctx) => {
|
|
2748
|
-
switch (ctx.type) {
|
|
2749
|
-
case "vertex-edit":
|
|
2750
|
-
return ctx.changes;
|
|
2751
|
-
case "move": {
|
|
2752
|
-
if (!ctx.changes.rect) return ctx.changes;
|
|
2753
|
-
const { dx, dy, rects } = baseMoveChanges(original, ctx.changes.rect);
|
|
2815
|
+
const isInsideStartHandle = (pos) => {
|
|
2816
|
+
const vertices = getVertices();
|
|
2817
|
+
if (vertices.length < 2) return false;
|
|
2818
|
+
const sizePDF = HANDLE_SIZE_PX / scale;
|
|
2819
|
+
const half = sizePDF / 2;
|
|
2820
|
+
const v0 = vertices[0];
|
|
2821
|
+
return pos.x >= v0.x - half && pos.x <= v0.x + half && pos.y >= v0.y - half && pos.y <= v0.y + half;
|
|
2822
|
+
};
|
|
2823
|
+
const getDefaults = () => {
|
|
2824
|
+
const tool = getTool();
|
|
2825
|
+
if (!tool) return null;
|
|
2754
2826
|
return {
|
|
2755
|
-
...
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2827
|
+
...tool.defaults,
|
|
2828
|
+
color: tool.defaults.color ?? "#000000",
|
|
2829
|
+
opacity: tool.defaults.opacity ?? 1,
|
|
2830
|
+
strokeWidth: tool.defaults.strokeWidth ?? 1,
|
|
2831
|
+
strokeColor: tool.defaults.strokeColor ?? "#000000",
|
|
2832
|
+
strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
|
|
2833
|
+
strokeDashArray: tool.defaults.strokeDashArray ?? [],
|
|
2834
|
+
flags: tool.defaults.flags ?? ["print"]
|
|
2759
2835
|
};
|
|
2760
|
-
}
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
);
|
|
2768
|
-
const
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2836
|
+
};
|
|
2837
|
+
const commitPolygon = () => {
|
|
2838
|
+
const vertices = getVertices();
|
|
2839
|
+
if (vertices.length < 3) return;
|
|
2840
|
+
const defaults = getDefaults();
|
|
2841
|
+
if (!defaults) return;
|
|
2842
|
+
const intensity = defaults.cloudyBorderIntensity ?? 0;
|
|
2843
|
+
const pad = intensity > 0 ? getCloudyBorderExtent(intensity, defaults.strokeWidth, false) : defaults.strokeWidth / 2;
|
|
2844
|
+
const rect = expandRect(rectFromPoints(vertices), pad);
|
|
2845
|
+
const anno = {
|
|
2846
|
+
...defaults,
|
|
2847
|
+
vertices,
|
|
2848
|
+
rect,
|
|
2849
|
+
type: PdfAnnotationSubtype.POLYGON,
|
|
2850
|
+
pageIndex: context.pageIndex,
|
|
2851
|
+
id: uuidV4(),
|
|
2852
|
+
created: /* @__PURE__ */ new Date(),
|
|
2853
|
+
...intensity > 0 && {
|
|
2854
|
+
rectangleDifferences: { left: pad, top: pad, right: pad, bottom: pad }
|
|
2773
2855
|
}
|
|
2774
|
-
});
|
|
2775
|
-
const resizeEpsilon = 1e-3;
|
|
2776
|
-
const widthChanged = Math.abs(scaleX - 1) > resizeEpsilon;
|
|
2777
|
-
const heightChanged = Math.abs(scaleY - 1) > resizeEpsilon;
|
|
2778
|
-
const strokeScale = widthChanged && !heightChanged ? scaleX : !widthChanged && heightChanged ? scaleY : Math.min(scaleX, scaleY);
|
|
2779
|
-
const rawStrokeWidth = Math.max(1, original.strokeWidth * strokeScale);
|
|
2780
|
-
const maxStrokeWidth = Math.max(
|
|
2781
|
-
1,
|
|
2782
|
-
Math.min(resolvedRect.size.width, resolvedRect.size.height)
|
|
2783
|
-
);
|
|
2784
|
-
const clampedStrokeWidth = Math.min(rawStrokeWidth, maxStrokeWidth);
|
|
2785
|
-
const newStrokeWidth = Number(clampedStrokeWidth.toFixed(1));
|
|
2786
|
-
const innerOld = inset(oldRect, original.strokeWidth / 2);
|
|
2787
|
-
const innerNew = inset(resolvedRect, newStrokeWidth / 2);
|
|
2788
|
-
const sx = innerNew.size.width / Math.max(innerOld.size.width, 1e-6);
|
|
2789
|
-
const sy = innerNew.size.height / Math.max(innerOld.size.height, 1e-6);
|
|
2790
|
-
return {
|
|
2791
|
-
...rects,
|
|
2792
|
-
inkList: original.inkList.map((stroke) => ({
|
|
2793
|
-
points: stroke.points.map((p) => ({
|
|
2794
|
-
x: innerNew.origin.x + (p.x - innerOld.origin.x) * sx,
|
|
2795
|
-
y: innerNew.origin.y + (p.y - innerOld.origin.y) * sy
|
|
2796
|
-
}))
|
|
2797
|
-
})),
|
|
2798
|
-
strokeWidth: newStrokeWidth
|
|
2799
2856
|
};
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2857
|
+
onCommit(anno);
|
|
2858
|
+
setVertices([]);
|
|
2859
|
+
setCurrent(null);
|
|
2860
|
+
onPreview(null);
|
|
2861
|
+
};
|
|
2862
|
+
const getPreview = () => {
|
|
2863
|
+
const vertices = getVertices();
|
|
2864
|
+
const currentPos = getCurrent();
|
|
2865
|
+
if (vertices.length === 0 || !currentPos) return null;
|
|
2866
|
+
const defaults = getDefaults();
|
|
2867
|
+
if (!defaults) return null;
|
|
2868
|
+
const intensity = defaults.cloudyBorderIntensity ?? 0;
|
|
2869
|
+
const pad = intensity > 0 ? getCloudyBorderExtent(intensity, defaults.strokeWidth, false) : defaults.strokeWidth / 2;
|
|
2870
|
+
const allPoints = [...vertices, currentPos];
|
|
2871
|
+
const bounds = expandRect(rectFromPoints(allPoints), pad);
|
|
2805
2872
|
return {
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2873
|
+
type: PdfAnnotationSubtype.POLYGON,
|
|
2874
|
+
bounds,
|
|
2875
|
+
data: {
|
|
2876
|
+
...defaults,
|
|
2877
|
+
rect: bounds,
|
|
2878
|
+
vertices,
|
|
2879
|
+
currentVertex: currentPos
|
|
2880
|
+
}
|
|
2810
2881
|
};
|
|
2811
|
-
}
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2882
|
+
};
|
|
2883
|
+
return {
|
|
2884
|
+
onClick: (pos, evt) => {
|
|
2885
|
+
if (evt.metaKey || evt.ctrlKey) {
|
|
2886
|
+
return;
|
|
2887
|
+
}
|
|
2888
|
+
const clampedPos = clampToPage(pos);
|
|
2889
|
+
if (isInsideStartHandle(clampedPos) && getVertices().length >= 3) {
|
|
2890
|
+
commitPolygon();
|
|
2891
|
+
return;
|
|
2892
|
+
}
|
|
2893
|
+
const vertices = getVertices();
|
|
2894
|
+
const lastVertex = vertices[vertices.length - 1];
|
|
2895
|
+
if (lastVertex && Math.abs(lastVertex.x - clampedPos.x) < 1 && Math.abs(lastVertex.y - clampedPos.y) < 1) {
|
|
2896
|
+
return;
|
|
2897
|
+
}
|
|
2898
|
+
setVertices([...vertices, clampedPos]);
|
|
2899
|
+
setCurrent(clampedPos);
|
|
2900
|
+
onPreview(getPreview());
|
|
2901
|
+
},
|
|
2902
|
+
onDoubleClick: (_) => {
|
|
2903
|
+
commitPolygon();
|
|
2904
|
+
},
|
|
2905
|
+
onPointerMove: (pos) => {
|
|
2906
|
+
if (getVertices().length > 0) {
|
|
2907
|
+
const clampedPos = clampToPage(pos);
|
|
2908
|
+
setCurrent(clampedPos);
|
|
2909
|
+
onPreview(getPreview());
|
|
2910
|
+
}
|
|
2911
|
+
},
|
|
2912
|
+
onPointerCancel: (_) => {
|
|
2913
|
+
setVertices([]);
|
|
2914
|
+
setCurrent(null);
|
|
2915
|
+
onPreview(null);
|
|
2829
2916
|
}
|
|
2830
|
-
|
|
2831
|
-
}
|
|
2832
|
-
default:
|
|
2833
|
-
return ctx.changes;
|
|
2917
|
+
};
|
|
2834
2918
|
}
|
|
2835
2919
|
};
|
|
2836
|
-
const
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2920
|
+
const squareHandlerFactory = {
|
|
2921
|
+
annotationType: PdfAnnotationSubtype.SQUARE,
|
|
2922
|
+
create(context) {
|
|
2923
|
+
const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
|
|
2924
|
+
const [getStart, setStart] = useState(null);
|
|
2925
|
+
const clampToPage = (pos) => ({
|
|
2926
|
+
x: clamp(pos.x, 0, pageSize.width),
|
|
2927
|
+
y: clamp(pos.y, 0, pageSize.height)
|
|
2928
|
+
});
|
|
2929
|
+
const getDefaults = () => {
|
|
2930
|
+
const tool = getTool();
|
|
2931
|
+
if (!tool) return null;
|
|
2932
|
+
return {
|
|
2933
|
+
...tool.defaults,
|
|
2934
|
+
flags: tool.defaults.flags ?? ["print"],
|
|
2935
|
+
strokeWidth: tool.defaults.strokeWidth ?? 2,
|
|
2936
|
+
strokeColor: tool.defaults.strokeColor ?? "#000000",
|
|
2937
|
+
strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
|
|
2938
|
+
strokeDashArray: tool.defaults.strokeDashArray ?? [],
|
|
2939
|
+
color: tool.defaults.color ?? "#000000",
|
|
2940
|
+
opacity: tool.defaults.opacity ?? 1
|
|
2941
|
+
};
|
|
2942
|
+
};
|
|
2943
|
+
const clickDetector = useClickDetector({
|
|
2944
|
+
threshold: 5,
|
|
2945
|
+
getTool,
|
|
2946
|
+
onClickDetected: (pos, tool) => {
|
|
2947
|
+
const defaults = getDefaults();
|
|
2948
|
+
if (!defaults) return;
|
|
2949
|
+
const clickConfig = tool.clickBehavior;
|
|
2950
|
+
if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
|
|
2951
|
+
const { width, height } = clickConfig.defaultSize;
|
|
2952
|
+
const halfWidth = width / 2;
|
|
2953
|
+
const halfHeight = height / 2;
|
|
2954
|
+
const x = clamp(pos.x - halfWidth, 0, pageSize.width - width);
|
|
2955
|
+
const y = clamp(pos.y - halfHeight, 0, pageSize.height - height);
|
|
2956
|
+
const strokeWidth = defaults.strokeWidth;
|
|
2957
|
+
const intensity = defaults.cloudyBorderIntensity ?? 0;
|
|
2958
|
+
const pad = intensity > 0 ? getCloudyBorderExtent(intensity, strokeWidth, false) : strokeWidth / 2;
|
|
2959
|
+
const rect = {
|
|
2960
|
+
origin: { x: x - pad, y: y - pad },
|
|
2961
|
+
size: { width: width + 2 * pad, height: height + 2 * pad }
|
|
2962
|
+
};
|
|
2963
|
+
const anno = {
|
|
2964
|
+
...defaults,
|
|
2965
|
+
type: PdfAnnotationSubtype.SQUARE,
|
|
2966
|
+
created: /* @__PURE__ */ new Date(),
|
|
2967
|
+
id: uuidV4(),
|
|
2968
|
+
pageIndex,
|
|
2969
|
+
rect,
|
|
2970
|
+
...intensity > 0 && {
|
|
2971
|
+
rectangleDifferences: { left: pad, top: pad, right: pad, bottom: pad }
|
|
2972
|
+
}
|
|
2848
2973
|
};
|
|
2974
|
+
onCommit(anno);
|
|
2849
2975
|
}
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2976
|
+
});
|
|
2977
|
+
const getPreview = (current) => {
|
|
2978
|
+
const p1 = getStart();
|
|
2979
|
+
if (!p1) return null;
|
|
2980
|
+
const minX = Math.min(p1.x, current.x);
|
|
2981
|
+
const minY = Math.min(p1.y, current.y);
|
|
2982
|
+
const width = Math.abs(p1.x - current.x);
|
|
2983
|
+
const height = Math.abs(p1.y - current.y);
|
|
2984
|
+
const defaults = getDefaults();
|
|
2985
|
+
if (!defaults) return null;
|
|
2986
|
+
const strokeWidth = defaults.strokeWidth;
|
|
2987
|
+
const intensity = defaults.cloudyBorderIntensity ?? 0;
|
|
2988
|
+
const pad = intensity > 0 ? getCloudyBorderExtent(intensity, strokeWidth, false) : strokeWidth / 2;
|
|
2989
|
+
const rect = {
|
|
2990
|
+
origin: { x: minX - pad, y: minY - pad },
|
|
2991
|
+
size: { width: width + 2 * pad, height: height + 2 * pad }
|
|
2992
|
+
};
|
|
2854
2993
|
return {
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2994
|
+
type: PdfAnnotationSubtype.SQUARE,
|
|
2995
|
+
bounds: rect,
|
|
2996
|
+
data: {
|
|
2997
|
+
rect,
|
|
2998
|
+
...defaults,
|
|
2999
|
+
...intensity > 0 && {
|
|
3000
|
+
rectangleDifferences: { left: pad, top: pad, right: pad, bottom: pad }
|
|
3001
|
+
}
|
|
2859
3002
|
}
|
|
2860
3003
|
};
|
|
2861
|
-
}
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
3004
|
+
};
|
|
3005
|
+
return {
|
|
3006
|
+
onPointerDown: (pos, evt) => {
|
|
3007
|
+
var _a;
|
|
3008
|
+
const clampedPos = clampToPage(pos);
|
|
3009
|
+
setStart(clampedPos);
|
|
3010
|
+
clickDetector.onStart(clampedPos);
|
|
3011
|
+
onPreview(getPreview(clampedPos));
|
|
3012
|
+
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
3013
|
+
},
|
|
3014
|
+
onPointerMove: (pos) => {
|
|
3015
|
+
const clampedPos = clampToPage(pos);
|
|
3016
|
+
clickDetector.onMove(clampedPos);
|
|
3017
|
+
if (getStart() && clickDetector.hasMoved()) {
|
|
3018
|
+
onPreview(getPreview(clampedPos));
|
|
3019
|
+
}
|
|
3020
|
+
},
|
|
3021
|
+
onPointerUp: (pos, evt) => {
|
|
3022
|
+
var _a;
|
|
3023
|
+
const p1 = getStart();
|
|
3024
|
+
if (!p1) return;
|
|
3025
|
+
const defaults = getDefaults();
|
|
3026
|
+
if (!defaults) return;
|
|
3027
|
+
const clampedPos = clampToPage(pos);
|
|
3028
|
+
if (!clickDetector.hasMoved()) {
|
|
3029
|
+
clickDetector.onEnd(clampedPos);
|
|
3030
|
+
} else {
|
|
3031
|
+
const defaults2 = getDefaults();
|
|
3032
|
+
if (!defaults2) return;
|
|
3033
|
+
const preview = getPreview(clampedPos);
|
|
3034
|
+
if (preview) {
|
|
3035
|
+
const intensity = defaults2.cloudyBorderIntensity ?? 0;
|
|
3036
|
+
const pad = intensity > 0 ? getCloudyBorderExtent(intensity, defaults2.strokeWidth, false) : void 0;
|
|
3037
|
+
const anno = {
|
|
3038
|
+
...defaults2,
|
|
3039
|
+
type: PdfAnnotationSubtype.SQUARE,
|
|
3040
|
+
created: /* @__PURE__ */ new Date(),
|
|
3041
|
+
id: uuidV4(),
|
|
3042
|
+
pageIndex,
|
|
3043
|
+
rect: preview.data.rect,
|
|
3044
|
+
...pad !== void 0 && {
|
|
3045
|
+
rectangleDifferences: { left: pad, top: pad, right: pad, bottom: pad }
|
|
3046
|
+
}
|
|
3047
|
+
};
|
|
3048
|
+
onCommit(anno);
|
|
2879
3049
|
}
|
|
2880
3050
|
}
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
3051
|
+
setStart(null);
|
|
3052
|
+
onPreview(null);
|
|
3053
|
+
clickDetector.reset();
|
|
3054
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
3055
|
+
},
|
|
3056
|
+
onPointerLeave: (_, evt) => {
|
|
3057
|
+
var _a;
|
|
3058
|
+
setStart(null);
|
|
3059
|
+
onPreview(null);
|
|
3060
|
+
clickDetector.reset();
|
|
3061
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
3062
|
+
},
|
|
3063
|
+
onPointerCancel: (_, evt) => {
|
|
3064
|
+
var _a;
|
|
3065
|
+
setStart(null);
|
|
3066
|
+
onPreview(null);
|
|
3067
|
+
clickDetector.reset();
|
|
3068
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
3069
|
+
}
|
|
3070
|
+
};
|
|
3071
|
+
}
|
|
3072
|
+
};
|
|
3073
|
+
const imageFetchCache = /* @__PURE__ */ new Map();
|
|
3074
|
+
const stampHandlerFactory = {
|
|
3075
|
+
annotationType: PdfAnnotationSubtype.STAMP,
|
|
3076
|
+
create(context) {
|
|
3077
|
+
const { services, onCommit, onPreview, getTool, pageSize, pageRotation } = context;
|
|
3078
|
+
let cachedBuffer = null;
|
|
3079
|
+
let cachedSize = null;
|
|
3080
|
+
const commitStamp = (pos, width, height, ctx) => {
|
|
3081
|
+
var _a;
|
|
3082
|
+
const tool = getTool();
|
|
3083
|
+
if (!tool) return;
|
|
3084
|
+
const rect = {
|
|
3085
|
+
origin: { x: pos.x - width / 2, y: pos.y - height / 2 },
|
|
3086
|
+
size: { width, height }
|
|
3087
|
+
};
|
|
3088
|
+
let anno = {
|
|
3089
|
+
...tool.defaults,
|
|
3090
|
+
rect,
|
|
3091
|
+
type: PdfAnnotationSubtype.STAMP,
|
|
3092
|
+
name: tool.defaults.name ?? PdfAnnotationName.Image,
|
|
3093
|
+
subject: tool.defaults.subject ?? "Stamp",
|
|
3094
|
+
flags: tool.defaults.flags ?? ["print"],
|
|
3095
|
+
pageIndex: context.pageIndex,
|
|
3096
|
+
id: uuidV4(),
|
|
3097
|
+
created: /* @__PURE__ */ new Date()
|
|
3098
|
+
};
|
|
3099
|
+
if ((_a = tool.behavior) == null ? void 0 : _a.insertUpright) {
|
|
3100
|
+
anno = applyInsertUpright(anno, pageRotation, false);
|
|
3101
|
+
}
|
|
3102
|
+
anno = clampAnnotationToPage(anno, pageSize);
|
|
3103
|
+
onCommit(anno, ctx);
|
|
3104
|
+
};
|
|
3105
|
+
const commitFromBuffer = (pos, buffer, imageSize) => {
|
|
3106
|
+
const meta = getImageMetadata(buffer);
|
|
3107
|
+
if (!meta || meta.mimeType === "application/pdf") return false;
|
|
3108
|
+
const fitted = fitSizeWithin(meta, pageSize);
|
|
3109
|
+
const width = (imageSize == null ? void 0 : imageSize.width) ?? fitted.width;
|
|
3110
|
+
const height = (imageSize == null ? void 0 : imageSize.height) ?? fitted.height;
|
|
3111
|
+
commitStamp(pos, width, height, { data: buffer });
|
|
3112
|
+
return true;
|
|
3113
|
+
};
|
|
3114
|
+
return {
|
|
3115
|
+
onHandlerActiveStart: () => {
|
|
3116
|
+
const tool = getTool();
|
|
3117
|
+
const imageSrc = tool == null ? void 0 : tool.defaults.imageSrc;
|
|
3118
|
+
if (!imageSrc) return;
|
|
3119
|
+
let entry = imageFetchCache.get(imageSrc);
|
|
3120
|
+
if (!entry) {
|
|
3121
|
+
const promise = fetch(imageSrc).then((res) => res.arrayBuffer()).then((buffer) => {
|
|
3122
|
+
const meta = getImageMetadata(buffer);
|
|
3123
|
+
if (!meta || meta.mimeType === "application/pdf") return null;
|
|
3124
|
+
const fitted = fitSizeWithin(meta, pageSize);
|
|
3125
|
+
const imageSize = tool.defaults.imageSize;
|
|
3126
|
+
return {
|
|
3127
|
+
buffer,
|
|
3128
|
+
width: (imageSize == null ? void 0 : imageSize.width) ?? fitted.width,
|
|
3129
|
+
height: (imageSize == null ? void 0 : imageSize.height) ?? fitted.height
|
|
3130
|
+
};
|
|
3131
|
+
}).catch(() => null);
|
|
3132
|
+
entry = { promise, refs: 1 };
|
|
3133
|
+
imageFetchCache.set(imageSrc, entry);
|
|
3134
|
+
} else {
|
|
3135
|
+
entry.refs++;
|
|
3136
|
+
}
|
|
3137
|
+
entry.promise.then((result) => {
|
|
3138
|
+
if (!result) return;
|
|
3139
|
+
cachedBuffer = result.buffer;
|
|
3140
|
+
cachedSize = { width: result.width, height: result.height };
|
|
3141
|
+
});
|
|
3142
|
+
},
|
|
3143
|
+
onHandlerActiveEnd: () => {
|
|
3144
|
+
const tool = getTool();
|
|
3145
|
+
const imageSrc = tool == null ? void 0 : tool.defaults.imageSrc;
|
|
3146
|
+
if (imageSrc) {
|
|
3147
|
+
const entry = imageFetchCache.get(imageSrc);
|
|
3148
|
+
if (entry && --entry.refs <= 0) {
|
|
3149
|
+
imageFetchCache.delete(imageSrc);
|
|
3150
|
+
}
|
|
2892
3151
|
}
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
const effectiveRotation = ctx.changes.rotation ?? orig.rotation ?? 0;
|
|
2905
|
-
if (orig.unrotatedRect || ctx.changes.rotation !== void 0) {
|
|
2906
|
-
return {
|
|
2907
|
-
...ctx.changes,
|
|
2908
|
-
unrotatedRect: tightRect,
|
|
2909
|
-
rect: calculateRotatedRectAABBAroundPoint(
|
|
2910
|
-
tightRect,
|
|
2911
|
-
effectiveRotation,
|
|
2912
|
-
resolveAnnotationRotationCenter(orig)
|
|
2913
|
-
)
|
|
3152
|
+
cachedBuffer = null;
|
|
3153
|
+
cachedSize = null;
|
|
3154
|
+
onPreview(null);
|
|
3155
|
+
},
|
|
3156
|
+
onPointerMove: (pos) => {
|
|
3157
|
+
var _a;
|
|
3158
|
+
const tool = getTool();
|
|
3159
|
+
if (!((_a = tool == null ? void 0 : tool.behavior) == null ? void 0 : _a.showGhost) || !cachedSize || !tool.defaults.imageSrc) return;
|
|
3160
|
+
const rect = {
|
|
3161
|
+
origin: { x: pos.x - cachedSize.width / 2, y: pos.y - cachedSize.height / 2 },
|
|
3162
|
+
size: cachedSize
|
|
2914
3163
|
};
|
|
3164
|
+
onPreview({
|
|
3165
|
+
type: PdfAnnotationSubtype.STAMP,
|
|
3166
|
+
bounds: rect,
|
|
3167
|
+
data: { rect, ghostUrl: tool.defaults.imageSrc, pageRotation }
|
|
3168
|
+
});
|
|
3169
|
+
},
|
|
3170
|
+
onPointerDown: (pos) => {
|
|
3171
|
+
const tool = getTool();
|
|
3172
|
+
if (!tool) return;
|
|
3173
|
+
const { imageSrc, imageSize } = tool.defaults;
|
|
3174
|
+
if (imageSrc) {
|
|
3175
|
+
onPreview(null);
|
|
3176
|
+
if (cachedBuffer) {
|
|
3177
|
+
commitFromBuffer(pos, cachedBuffer, imageSize);
|
|
3178
|
+
} else {
|
|
3179
|
+
fetch(imageSrc).then((res) => res.arrayBuffer()).then((buffer) => commitFromBuffer(pos, buffer, imageSize));
|
|
3180
|
+
}
|
|
3181
|
+
} else {
|
|
3182
|
+
services.requestFile({
|
|
3183
|
+
accept: "image/png,image/jpeg",
|
|
3184
|
+
onFile: (file) => {
|
|
3185
|
+
file.arrayBuffer().then((buffer) => commitFromBuffer(pos, buffer));
|
|
3186
|
+
}
|
|
3187
|
+
});
|
|
3188
|
+
}
|
|
3189
|
+
},
|
|
3190
|
+
onPointerLeave: () => {
|
|
3191
|
+
onPreview(null);
|
|
2915
3192
|
}
|
|
2916
|
-
|
|
2917
|
-
}
|
|
2918
|
-
default:
|
|
2919
|
-
return ctx.changes;
|
|
3193
|
+
};
|
|
2920
3194
|
}
|
|
2921
3195
|
};
|
|
2922
|
-
const
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
}
|
|
2935
|
-
return ctx.changes;
|
|
2936
|
-
case "move": {
|
|
2937
|
-
if (!ctx.changes.rect) return ctx.changes;
|
|
2938
|
-
const { dx, dy, rects } = baseMoveChanges(orig, ctx.changes.rect);
|
|
3196
|
+
const circleHandlerFactory = {
|
|
3197
|
+
annotationType: PdfAnnotationSubtype.CIRCLE,
|
|
3198
|
+
create(context) {
|
|
3199
|
+
const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
|
|
3200
|
+
const [getStart, setStart] = useState(null);
|
|
3201
|
+
const clampToPage = (pos) => ({
|
|
3202
|
+
x: clamp(pos.x, 0, pageSize.width),
|
|
3203
|
+
y: clamp(pos.y, 0, pageSize.height)
|
|
3204
|
+
});
|
|
3205
|
+
const getDefaults = () => {
|
|
3206
|
+
const tool = getTool();
|
|
3207
|
+
if (!tool) return null;
|
|
2939
3208
|
return {
|
|
2940
|
-
...
|
|
2941
|
-
|
|
3209
|
+
...tool.defaults,
|
|
3210
|
+
strokeWidth: tool.defaults.strokeWidth ?? 2,
|
|
3211
|
+
strokeColor: tool.defaults.strokeColor ?? "#000000",
|
|
3212
|
+
strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
|
|
3213
|
+
strokeDashArray: tool.defaults.strokeDashArray ?? [],
|
|
3214
|
+
color: tool.defaults.color ?? "#000000",
|
|
3215
|
+
opacity: tool.defaults.opacity ?? 1,
|
|
3216
|
+
flags: tool.defaults.flags ?? ["print"]
|
|
2942
3217
|
};
|
|
2943
|
-
}
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
3218
|
+
};
|
|
3219
|
+
const clickDetector = useClickDetector({
|
|
3220
|
+
threshold: 5,
|
|
3221
|
+
getTool,
|
|
3222
|
+
onClickDetected: (pos, tool) => {
|
|
3223
|
+
const defaults = getDefaults();
|
|
3224
|
+
if (!defaults) return;
|
|
3225
|
+
const clickConfig = tool.clickBehavior;
|
|
3226
|
+
if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
|
|
3227
|
+
const { width, height } = clickConfig.defaultSize;
|
|
3228
|
+
const halfWidth = width / 2;
|
|
3229
|
+
const halfHeight = height / 2;
|
|
3230
|
+
const x = clamp(pos.x - halfWidth, 0, pageSize.width - width);
|
|
3231
|
+
const y = clamp(pos.y - halfHeight, 0, pageSize.height - height);
|
|
3232
|
+
const strokeWidth = defaults.strokeWidth;
|
|
3233
|
+
const intensity = defaults.cloudyBorderIntensity ?? 0;
|
|
3234
|
+
const pad = intensity > 0 ? getCloudyBorderExtent(intensity, strokeWidth, true) : strokeWidth / 2;
|
|
3235
|
+
const rect = {
|
|
3236
|
+
origin: { x: x - pad, y: y - pad },
|
|
3237
|
+
size: { width: width + 2 * pad, height: height + 2 * pad }
|
|
3238
|
+
};
|
|
3239
|
+
const anno = {
|
|
3240
|
+
...defaults,
|
|
3241
|
+
type: PdfAnnotationSubtype.CIRCLE,
|
|
3242
|
+
created: /* @__PURE__ */ new Date(),
|
|
3243
|
+
id: uuidV4(),
|
|
3244
|
+
pageIndex,
|
|
3245
|
+
rect,
|
|
3246
|
+
...intensity > 0 && {
|
|
3247
|
+
rectangleDifferences: { left: pad, top: pad, right: pad, bottom: pad }
|
|
3248
|
+
}
|
|
3249
|
+
};
|
|
3250
|
+
onCommit(anno);
|
|
3251
|
+
}
|
|
3252
|
+
});
|
|
3253
|
+
const getPreview = (current) => {
|
|
3254
|
+
const p1 = getStart();
|
|
3255
|
+
if (!p1) return null;
|
|
3256
|
+
const minX = Math.min(p1.x, current.x);
|
|
3257
|
+
const minY = Math.min(p1.y, current.y);
|
|
3258
|
+
const width = Math.abs(p1.x - current.x);
|
|
3259
|
+
const height = Math.abs(p1.y - current.y);
|
|
3260
|
+
const defaults = getDefaults();
|
|
3261
|
+
if (!defaults) return null;
|
|
3262
|
+
const strokeWidth = defaults.strokeWidth;
|
|
3263
|
+
const intensity = defaults.cloudyBorderIntensity ?? 0;
|
|
3264
|
+
const pad = intensity > 0 ? getCloudyBorderExtent(intensity, strokeWidth, true) : strokeWidth / 2;
|
|
3265
|
+
const rect = {
|
|
3266
|
+
origin: { x: minX - pad, y: minY - pad },
|
|
3267
|
+
size: { width: width + 2 * pad, height: height + 2 * pad }
|
|
2957
3268
|
};
|
|
2958
|
-
}
|
|
2959
|
-
case "rotate": {
|
|
2960
|
-
const result = baseRotateChanges(orig, ctx);
|
|
2961
|
-
if (!result) return ctx.changes;
|
|
2962
|
-
const { dx, dy } = rotateOrbitDelta(orig, result);
|
|
2963
3269
|
return {
|
|
2964
|
-
|
|
2965
|
-
|
|
3270
|
+
type: PdfAnnotationSubtype.CIRCLE,
|
|
3271
|
+
bounds: rect,
|
|
3272
|
+
data: {
|
|
3273
|
+
rect,
|
|
3274
|
+
...defaults,
|
|
3275
|
+
...intensity > 0 && {
|
|
3276
|
+
rectangleDifferences: { left: pad, top: pad, right: pad, bottom: pad }
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
2966
3279
|
};
|
|
2967
|
-
}
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
3280
|
+
};
|
|
3281
|
+
return {
|
|
3282
|
+
onPointerDown: (pos, evt) => {
|
|
3283
|
+
var _a;
|
|
3284
|
+
const clampedPos = clampToPage(pos);
|
|
3285
|
+
setStart(clampedPos);
|
|
3286
|
+
clickDetector.onStart(clampedPos);
|
|
3287
|
+
onPreview(getPreview(clampedPos));
|
|
3288
|
+
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
3289
|
+
},
|
|
3290
|
+
onPointerMove: (pos) => {
|
|
3291
|
+
const clampedPos = clampToPage(pos);
|
|
3292
|
+
clickDetector.onMove(clampedPos);
|
|
3293
|
+
if (getStart() && clickDetector.hasMoved()) {
|
|
3294
|
+
onPreview(getPreview(clampedPos));
|
|
3295
|
+
}
|
|
3296
|
+
},
|
|
3297
|
+
onPointerUp: (pos, evt) => {
|
|
3298
|
+
var _a;
|
|
3299
|
+
const p1 = getStart();
|
|
3300
|
+
if (!p1) return;
|
|
3301
|
+
const defaults = getDefaults();
|
|
3302
|
+
if (!defaults) return;
|
|
3303
|
+
const clampedPos = clampToPage(pos);
|
|
3304
|
+
if (!clickDetector.hasMoved()) {
|
|
3305
|
+
clickDetector.onEnd(clampedPos);
|
|
3306
|
+
} else {
|
|
3307
|
+
const defaults2 = getDefaults();
|
|
3308
|
+
if (!defaults2) return;
|
|
3309
|
+
const preview = getPreview(clampedPos);
|
|
3310
|
+
if (preview) {
|
|
3311
|
+
const intensity = defaults2.cloudyBorderIntensity ?? 0;
|
|
3312
|
+
const pad = intensity > 0 ? getCloudyBorderExtent(intensity, defaults2.strokeWidth, true) : void 0;
|
|
3313
|
+
const anno = {
|
|
3314
|
+
...defaults2,
|
|
3315
|
+
type: PdfAnnotationSubtype.CIRCLE,
|
|
3316
|
+
flags: ["print"],
|
|
3317
|
+
created: /* @__PURE__ */ new Date(),
|
|
3318
|
+
id: uuidV4(),
|
|
3319
|
+
pageIndex,
|
|
3320
|
+
rect: preview.data.rect,
|
|
3321
|
+
...pad !== void 0 && {
|
|
3322
|
+
rectangleDifferences: { left: pad, top: pad, right: pad, bottom: pad }
|
|
3323
|
+
}
|
|
3324
|
+
};
|
|
3325
|
+
onCommit(anno);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
setStart(null);
|
|
3329
|
+
onPreview(null);
|
|
3330
|
+
clickDetector.reset();
|
|
3331
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
3332
|
+
},
|
|
3333
|
+
onPointerLeave: (_, evt) => {
|
|
3334
|
+
var _a;
|
|
3335
|
+
setStart(null);
|
|
3336
|
+
onPreview(null);
|
|
3337
|
+
clickDetector.reset();
|
|
3338
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
3339
|
+
},
|
|
3340
|
+
onPointerCancel: (_, evt) => {
|
|
3341
|
+
var _a;
|
|
3342
|
+
setStart(null);
|
|
3343
|
+
onPreview(null);
|
|
3344
|
+
clickDetector.reset();
|
|
3345
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
2988
3346
|
}
|
|
2989
|
-
|
|
2990
|
-
}
|
|
2991
|
-
default:
|
|
2992
|
-
return ctx.changes;
|
|
3347
|
+
};
|
|
2993
3348
|
}
|
|
2994
3349
|
};
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
const rawRect = expandRect(rectFromPoints(rawVertices), pad);
|
|
3008
|
-
const compensated = compensateRotatedVertexEdit(orig, rawVertices, rawRect);
|
|
3009
|
-
const rect = expandRect(rectFromPoints(compensated), pad);
|
|
3010
|
-
return {
|
|
3011
|
-
...resolveVertexEditRects(orig, rect),
|
|
3012
|
-
vertices: compensated
|
|
3013
|
-
};
|
|
3014
|
-
}
|
|
3015
|
-
return ctx.changes;
|
|
3016
|
-
case "move": {
|
|
3017
|
-
if (!ctx.changes.rect) return ctx.changes;
|
|
3018
|
-
const { dx, dy, rects } = baseMoveChanges(orig, ctx.changes.rect);
|
|
3350
|
+
const linkHandlerFactory = {
|
|
3351
|
+
annotationType: PdfAnnotationSubtype.LINK,
|
|
3352
|
+
create(context) {
|
|
3353
|
+
const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
|
|
3354
|
+
const [getStart, setStart] = useState(null);
|
|
3355
|
+
const clampToPage = (pos) => ({
|
|
3356
|
+
x: clamp(pos.x, 0, pageSize.width),
|
|
3357
|
+
y: clamp(pos.y, 0, pageSize.height)
|
|
3358
|
+
});
|
|
3359
|
+
const getDefaults = () => {
|
|
3360
|
+
const tool = getTool();
|
|
3361
|
+
if (!tool) return null;
|
|
3019
3362
|
return {
|
|
3020
|
-
...
|
|
3021
|
-
|
|
3363
|
+
...tool.defaults,
|
|
3364
|
+
flags: tool.defaults.flags ?? ["print"],
|
|
3365
|
+
strokeWidth: tool.defaults.strokeWidth ?? 2,
|
|
3366
|
+
strokeColor: tool.defaults.strokeColor ?? "#0000FF",
|
|
3367
|
+
strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.UNDERLINE,
|
|
3368
|
+
strokeDashArray: tool.defaults.strokeDashArray ?? []
|
|
3022
3369
|
};
|
|
3023
|
-
}
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3370
|
+
};
|
|
3371
|
+
const clickDetector = useClickDetector({
|
|
3372
|
+
threshold: 5,
|
|
3373
|
+
getTool,
|
|
3374
|
+
onClickDetected: (pos, tool) => {
|
|
3375
|
+
const defaults = getDefaults();
|
|
3376
|
+
if (!defaults) return;
|
|
3377
|
+
const clickConfig = tool.clickBehavior;
|
|
3378
|
+
if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
|
|
3379
|
+
const { width, height } = clickConfig.defaultSize;
|
|
3380
|
+
const halfWidth = width / 2;
|
|
3381
|
+
const halfHeight = height / 2;
|
|
3382
|
+
const x = clamp(pos.x - halfWidth, 0, pageSize.width - width);
|
|
3383
|
+
const y = clamp(pos.y - halfHeight, 0, pageSize.height - height);
|
|
3384
|
+
const rect = {
|
|
3385
|
+
origin: { x, y },
|
|
3386
|
+
size: { width, height }
|
|
3387
|
+
};
|
|
3388
|
+
const anno = {
|
|
3389
|
+
...defaults,
|
|
3390
|
+
type: PdfAnnotationSubtype.LINK,
|
|
3391
|
+
target: void 0,
|
|
3392
|
+
created: /* @__PURE__ */ new Date(),
|
|
3393
|
+
id: uuidV4(),
|
|
3394
|
+
pageIndex,
|
|
3395
|
+
rect
|
|
3396
|
+
};
|
|
3397
|
+
onCommit(anno);
|
|
3398
|
+
}
|
|
3399
|
+
});
|
|
3400
|
+
const getPreview = (current) => {
|
|
3401
|
+
const p1 = getStart();
|
|
3402
|
+
if (!p1) return null;
|
|
3403
|
+
const minX = Math.min(p1.x, current.x);
|
|
3404
|
+
const minY = Math.min(p1.y, current.y);
|
|
3405
|
+
const width = Math.abs(p1.x - current.x);
|
|
3406
|
+
const height = Math.abs(p1.y - current.y);
|
|
3407
|
+
const defaults = getDefaults();
|
|
3408
|
+
if (!defaults) return null;
|
|
3409
|
+
const rect = {
|
|
3410
|
+
origin: { x: minX, y: minY },
|
|
3411
|
+
size: { width, height }
|
|
3037
3412
|
};
|
|
3038
|
-
}
|
|
3039
|
-
case "rotate": {
|
|
3040
|
-
const result = baseRotateChanges(orig, ctx);
|
|
3041
|
-
if (!result) return ctx.changes;
|
|
3042
|
-
const { dx, dy } = rotateOrbitDelta(orig, result);
|
|
3043
3413
|
return {
|
|
3044
|
-
|
|
3045
|
-
|
|
3414
|
+
type: PdfAnnotationSubtype.LINK,
|
|
3415
|
+
bounds: rect,
|
|
3416
|
+
data: {
|
|
3417
|
+
rect,
|
|
3418
|
+
strokeColor: defaults.strokeColor,
|
|
3419
|
+
strokeWidth: defaults.strokeWidth,
|
|
3420
|
+
strokeStyle: defaults.strokeStyle,
|
|
3421
|
+
strokeDashArray: defaults.strokeDashArray
|
|
3422
|
+
}
|
|
3046
3423
|
};
|
|
3047
|
-
}
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
const
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
...patch,
|
|
3063
|
-
rectangleDifferences: { left: extent, top: extent, right: extent, bottom: extent }
|
|
3064
|
-
};
|
|
3065
|
-
} else {
|
|
3066
|
-
patch = { ...patch, rectangleDifferences: void 0 };
|
|
3424
|
+
};
|
|
3425
|
+
return {
|
|
3426
|
+
onPointerDown: (pos, evt) => {
|
|
3427
|
+
var _a;
|
|
3428
|
+
const clampedPos = clampToPage(pos);
|
|
3429
|
+
setStart(clampedPos);
|
|
3430
|
+
clickDetector.onStart(clampedPos);
|
|
3431
|
+
onPreview(getPreview(clampedPos));
|
|
3432
|
+
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
3433
|
+
},
|
|
3434
|
+
onPointerMove: (pos) => {
|
|
3435
|
+
const clampedPos = clampToPage(pos);
|
|
3436
|
+
clickDetector.onMove(clampedPos);
|
|
3437
|
+
if (getStart() && clickDetector.hasMoved()) {
|
|
3438
|
+
onPreview(getPreview(clampedPos));
|
|
3067
3439
|
}
|
|
3068
|
-
}
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
)
|
|
3079
|
-
};
|
|
3080
|
-
}
|
|
3081
|
-
return { ...patch, rect: tightRect };
|
|
3082
|
-
}
|
|
3083
|
-
default:
|
|
3084
|
-
return ctx.changes;
|
|
3085
|
-
}
|
|
3086
|
-
};
|
|
3087
|
-
const patchCircle = (orig, ctx) => {
|
|
3088
|
-
switch (ctx.type) {
|
|
3089
|
-
case "move":
|
|
3090
|
-
if (!ctx.changes.rect) return ctx.changes;
|
|
3091
|
-
return baseMoveChanges(orig, ctx.changes.rect).rects;
|
|
3092
|
-
case "resize":
|
|
3093
|
-
if (!ctx.changes.rect) return ctx.changes;
|
|
3094
|
-
return baseResizeScaling(orig, ctx.changes.rect, ctx.metadata).rects;
|
|
3095
|
-
case "rotate":
|
|
3096
|
-
return baseRotateChanges(orig, ctx) ?? ctx.changes;
|
|
3097
|
-
case "property-update": {
|
|
3098
|
-
let patch = ctx.changes;
|
|
3099
|
-
const cloudyChanged = ctx.changes.cloudyBorderIntensity !== void 0;
|
|
3100
|
-
const strokeChanged = ctx.changes.strokeWidth !== void 0;
|
|
3101
|
-
const hasCloudy = (orig.cloudyBorderIntensity ?? 0) > 0;
|
|
3102
|
-
if (cloudyChanged || strokeChanged && hasCloudy) {
|
|
3103
|
-
const merged = { ...orig, ...ctx.changes };
|
|
3104
|
-
const intensity = merged.cloudyBorderIntensity ?? 0;
|
|
3105
|
-
if (intensity > 0) {
|
|
3106
|
-
const extent = getCloudyBorderExtent(intensity, merged.strokeWidth, true);
|
|
3107
|
-
patch = {
|
|
3108
|
-
...patch,
|
|
3109
|
-
rectangleDifferences: { left: extent, top: extent, right: extent, bottom: extent }
|
|
3110
|
-
};
|
|
3440
|
+
},
|
|
3441
|
+
onPointerUp: (pos, evt) => {
|
|
3442
|
+
var _a;
|
|
3443
|
+
const p1 = getStart();
|
|
3444
|
+
if (!p1) return;
|
|
3445
|
+
const defaults = getDefaults();
|
|
3446
|
+
if (!defaults) return;
|
|
3447
|
+
const clampedPos = clampToPage(pos);
|
|
3448
|
+
if (!clickDetector.hasMoved()) {
|
|
3449
|
+
clickDetector.onEnd(clampedPos);
|
|
3111
3450
|
} else {
|
|
3112
|
-
|
|
3451
|
+
const preview = getPreview(clampedPos);
|
|
3452
|
+
if (preview) {
|
|
3453
|
+
const anno = {
|
|
3454
|
+
...defaults,
|
|
3455
|
+
type: PdfAnnotationSubtype.LINK,
|
|
3456
|
+
target: void 0,
|
|
3457
|
+
created: /* @__PURE__ */ new Date(),
|
|
3458
|
+
id: uuidV4(),
|
|
3459
|
+
pageIndex,
|
|
3460
|
+
rect: preview.data.rect
|
|
3461
|
+
};
|
|
3462
|
+
onCommit(anno);
|
|
3463
|
+
}
|
|
3113
3464
|
}
|
|
3465
|
+
setStart(null);
|
|
3466
|
+
onPreview(null);
|
|
3467
|
+
clickDetector.reset();
|
|
3468
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
3469
|
+
},
|
|
3470
|
+
onPointerLeave: (_, evt) => {
|
|
3471
|
+
var _a;
|
|
3472
|
+
setStart(null);
|
|
3473
|
+
onPreview(null);
|
|
3474
|
+
clickDetector.reset();
|
|
3475
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
3476
|
+
},
|
|
3477
|
+
onPointerCancel: (_, evt) => {
|
|
3478
|
+
var _a;
|
|
3479
|
+
setStart(null);
|
|
3480
|
+
onPreview(null);
|
|
3481
|
+
clickDetector.reset();
|
|
3482
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
3114
3483
|
}
|
|
3115
|
-
|
|
3116
|
-
patch = { ...patch, ...basePropertyRotationChanges(orig, ctx.changes.rotation) };
|
|
3117
|
-
}
|
|
3118
|
-
return patch;
|
|
3119
|
-
}
|
|
3120
|
-
default:
|
|
3121
|
-
return ctx.changes;
|
|
3484
|
+
};
|
|
3122
3485
|
}
|
|
3123
3486
|
};
|
|
3124
|
-
const
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
if (
|
|
3143
|
-
|
|
3144
|
-
patch = {
|
|
3145
|
-
...patch,
|
|
3146
|
-
rectangleDifferences: { left: extent, top: extent, right: extent, bottom: extent }
|
|
3147
|
-
};
|
|
3148
|
-
} else {
|
|
3149
|
-
patch = { ...patch, rectangleDifferences: void 0 };
|
|
3487
|
+
const textMarkupSelectionHandler = {
|
|
3488
|
+
toolId: "__textMarkup__",
|
|
3489
|
+
handle(context, selections, getText) {
|
|
3490
|
+
const tool = context.getTool();
|
|
3491
|
+
if (!tool) return;
|
|
3492
|
+
for (const selection of selections) {
|
|
3493
|
+
const id = uuidV4();
|
|
3494
|
+
getText().then((text) => {
|
|
3495
|
+
var _a;
|
|
3496
|
+
context.createAnnotation(selection.pageIndex, {
|
|
3497
|
+
...tool.defaults,
|
|
3498
|
+
rect: selection.rect,
|
|
3499
|
+
segmentRects: selection.segmentRects,
|
|
3500
|
+
pageIndex: selection.pageIndex,
|
|
3501
|
+
created: /* @__PURE__ */ new Date(),
|
|
3502
|
+
id,
|
|
3503
|
+
...text != null && { custom: { text } }
|
|
3504
|
+
});
|
|
3505
|
+
if ((_a = tool.behavior) == null ? void 0 : _a.selectAfterCreate) {
|
|
3506
|
+
context.selectAnnotation(selection.pageIndex, id);
|
|
3150
3507
|
}
|
|
3151
|
-
}
|
|
3152
|
-
if (ctx.changes.rotation !== void 0) {
|
|
3153
|
-
patch = { ...patch, ...basePropertyRotationChanges(orig, ctx.changes.rotation) };
|
|
3154
|
-
}
|
|
3155
|
-
return patch;
|
|
3508
|
+
});
|
|
3156
3509
|
}
|
|
3157
|
-
default:
|
|
3158
|
-
return ctx.changes;
|
|
3159
3510
|
}
|
|
3160
3511
|
};
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3512
|
+
function computeCaretRect(lastSegRect) {
|
|
3513
|
+
const lineHeight = lastSegRect.size.height;
|
|
3514
|
+
const height = lineHeight / 2;
|
|
3515
|
+
const width = height;
|
|
3516
|
+
const lineEndX = lastSegRect.origin.x + lastSegRect.size.width;
|
|
3517
|
+
return {
|
|
3518
|
+
origin: {
|
|
3519
|
+
x: lineEndX - width / 2,
|
|
3520
|
+
y: lastSegRect.origin.y + lineHeight / 2
|
|
3521
|
+
},
|
|
3522
|
+
size: { width, height }
|
|
3523
|
+
};
|
|
3524
|
+
}
|
|
3525
|
+
const insertTextSelectionHandler = {
|
|
3526
|
+
toolId: "insertText",
|
|
3527
|
+
handle(context, selections, getText) {
|
|
3528
|
+
const tool = context.getTool();
|
|
3529
|
+
if (!tool) return;
|
|
3530
|
+
const getDefaults = () => ({
|
|
3531
|
+
strokeColor: tool.defaults.strokeColor ?? "#E44234",
|
|
3532
|
+
opacity: tool.defaults.opacity ?? 1,
|
|
3533
|
+
flags: tool.defaults.flags ?? ["print"]
|
|
3534
|
+
});
|
|
3535
|
+
for (const selection of selections) {
|
|
3536
|
+
const lastSegRect = selection.segmentRects[selection.segmentRects.length - 1];
|
|
3537
|
+
if (!lastSegRect) continue;
|
|
3538
|
+
const caretRect = computeCaretRect(lastSegRect);
|
|
3539
|
+
const caretId = uuidV4();
|
|
3540
|
+
const defaults = getDefaults();
|
|
3541
|
+
getText().then((text) => {
|
|
3542
|
+
var _a;
|
|
3543
|
+
context.createAnnotation(selection.pageIndex, {
|
|
3544
|
+
type: PdfAnnotationSubtype.CARET,
|
|
3545
|
+
id: caretId,
|
|
3546
|
+
pageIndex: selection.pageIndex,
|
|
3547
|
+
rect: caretRect,
|
|
3548
|
+
strokeColor: defaults.strokeColor,
|
|
3549
|
+
opacity: defaults.opacity,
|
|
3550
|
+
intent: "Insert",
|
|
3551
|
+
rectangleDifferences: { left: 0.5, top: 0.5, right: 0.5, bottom: 0.5 },
|
|
3552
|
+
created: /* @__PURE__ */ new Date(),
|
|
3553
|
+
flags: defaults.flags,
|
|
3554
|
+
...text != null && { custom: { text } }
|
|
3555
|
+
});
|
|
3556
|
+
if ((_a = tool.behavior) == null ? void 0 : _a.selectAfterCreate) {
|
|
3557
|
+
context.selectAnnotation(selection.pageIndex, caretId);
|
|
3558
|
+
}
|
|
3559
|
+
});
|
|
3560
|
+
}
|
|
3178
3561
|
}
|
|
3179
3562
|
};
|
|
3180
|
-
const
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3563
|
+
const replaceTextSelectionHandler = {
|
|
3564
|
+
toolId: "replaceText",
|
|
3565
|
+
handle(context, selections, getText) {
|
|
3566
|
+
const tool = context.getTool();
|
|
3567
|
+
if (!tool) return;
|
|
3568
|
+
const getDefaults = () => ({
|
|
3569
|
+
strokeColor: tool.defaults.strokeColor ?? "#E44234",
|
|
3570
|
+
opacity: tool.defaults.opacity ?? 1,
|
|
3571
|
+
flags: tool.defaults.flags ?? ["print"]
|
|
3572
|
+
});
|
|
3573
|
+
for (const selection of selections) {
|
|
3574
|
+
const lastSegRect = selection.segmentRects[selection.segmentRects.length - 1];
|
|
3575
|
+
if (!lastSegRect) continue;
|
|
3576
|
+
const caretRect = computeCaretRect(lastSegRect);
|
|
3577
|
+
const caretId = uuidV4();
|
|
3578
|
+
const strikeoutId = uuidV4();
|
|
3579
|
+
const defaults = getDefaults();
|
|
3580
|
+
getText().then((text) => {
|
|
3581
|
+
var _a;
|
|
3582
|
+
context.createAnnotation(selection.pageIndex, {
|
|
3583
|
+
type: PdfAnnotationSubtype.CARET,
|
|
3584
|
+
id: caretId,
|
|
3585
|
+
pageIndex: selection.pageIndex,
|
|
3586
|
+
rect: caretRect,
|
|
3587
|
+
strokeColor: defaults.strokeColor,
|
|
3588
|
+
opacity: defaults.opacity,
|
|
3589
|
+
intent: "Replace",
|
|
3590
|
+
rectangleDifferences: { left: 0.5, top: 0.5, right: 0.5, bottom: 0.5 },
|
|
3591
|
+
created: /* @__PURE__ */ new Date(),
|
|
3592
|
+
flags: defaults.flags
|
|
3593
|
+
});
|
|
3594
|
+
context.createAnnotation(selection.pageIndex, {
|
|
3595
|
+
type: PdfAnnotationSubtype.STRIKEOUT,
|
|
3596
|
+
id: strikeoutId,
|
|
3597
|
+
pageIndex: selection.pageIndex,
|
|
3598
|
+
rect: selection.rect,
|
|
3599
|
+
segmentRects: selection.segmentRects,
|
|
3600
|
+
strokeColor: defaults.strokeColor,
|
|
3601
|
+
opacity: defaults.opacity,
|
|
3602
|
+
intent: "StrikeOutTextEdit",
|
|
3603
|
+
inReplyToId: caretId,
|
|
3604
|
+
replyType: PdfAnnotationReplyType.Group,
|
|
3605
|
+
created: /* @__PURE__ */ new Date(),
|
|
3606
|
+
flags: defaults.flags,
|
|
3607
|
+
...text != null && { custom: { text } }
|
|
3608
|
+
});
|
|
3609
|
+
if ((_a = tool.behavior) == null ? void 0 : _a.selectAfterCreate) {
|
|
3610
|
+
context.selectAnnotation(selection.pageIndex, caretId);
|
|
3611
|
+
}
|
|
3612
|
+
});
|
|
3613
|
+
}
|
|
3197
3614
|
}
|
|
3198
3615
|
};
|
|
3199
3616
|
const textMarkupTools = [
|
|
@@ -3657,7 +4074,7 @@ const freeTextTools = [
|
|
|
3657
4074
|
name: "Free Text",
|
|
3658
4075
|
labelKey: "annotation.freeText",
|
|
3659
4076
|
categories: ["annotation", "markup"],
|
|
3660
|
-
matchScore: (a) => a.type === PdfAnnotationSubtype.FREETEXT ? 1 : 0,
|
|
4077
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.FREETEXT && a.intent !== "FreeTextCallout" ? 1 : 0,
|
|
3661
4078
|
interaction: {
|
|
3662
4079
|
exclusive: false,
|
|
3663
4080
|
cursor: "crosshair",
|
|
@@ -3697,6 +4114,44 @@ const freeTextTools = [
|
|
|
3697
4114
|
pointerHandler: freeTextHandlerFactory
|
|
3698
4115
|
}
|
|
3699
4116
|
];
|
|
4117
|
+
const calloutFreeTextTools = [
|
|
4118
|
+
{
|
|
4119
|
+
id: "freeTextCallout",
|
|
4120
|
+
name: "Callout",
|
|
4121
|
+
labelKey: "annotation.callout",
|
|
4122
|
+
categories: ["annotation", "markup"],
|
|
4123
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.FREETEXT && a.intent === "FreeTextCallout" ? 10 : 0,
|
|
4124
|
+
interaction: {
|
|
4125
|
+
exclusive: false,
|
|
4126
|
+
cursor: "crosshair",
|
|
4127
|
+
isDraggable: true,
|
|
4128
|
+
isResizable: false,
|
|
4129
|
+
isRotatable: false
|
|
4130
|
+
},
|
|
4131
|
+
defaults: {
|
|
4132
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
4133
|
+
intent: "FreeTextCallout",
|
|
4134
|
+
contents: "Insert text",
|
|
4135
|
+
fontSize: 14,
|
|
4136
|
+
fontColor: "#E44234",
|
|
4137
|
+
fontFamily: PdfStandardFont.Helvetica,
|
|
4138
|
+
textAlign: PdfTextAlignment.Left,
|
|
4139
|
+
verticalAlign: PdfVerticalAlignment.Top,
|
|
4140
|
+
color: "transparent",
|
|
4141
|
+
opacity: 1,
|
|
4142
|
+
lineEnding: PdfAnnotationLineEnding.OpenArrow,
|
|
4143
|
+
strokeColor: "#E44234",
|
|
4144
|
+
strokeWidth: 1
|
|
4145
|
+
},
|
|
4146
|
+
behavior: {
|
|
4147
|
+
insertUpright: true,
|
|
4148
|
+
editAfterCreate: true,
|
|
4149
|
+
selectAfterCreate: true
|
|
4150
|
+
},
|
|
4151
|
+
transform: patchCalloutFreeText,
|
|
4152
|
+
pointerHandler: calloutFreeTextHandlerFactory
|
|
4153
|
+
}
|
|
4154
|
+
];
|
|
3700
4155
|
const stampTools = [
|
|
3701
4156
|
{
|
|
3702
4157
|
id: "stamp",
|
|
@@ -3763,6 +4218,7 @@ const defaultTools = [
|
|
|
3763
4218
|
...polygonTools,
|
|
3764
4219
|
...textCommentTools,
|
|
3765
4220
|
...freeTextTools,
|
|
4221
|
+
...calloutFreeTextTools,
|
|
3766
4222
|
...stampTools,
|
|
3767
4223
|
...linkTools
|
|
3768
4224
|
];
|