@embedpdf/plugin-annotation 1.0.7 → 1.0.9
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 +48 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -7
- package/dist/index.d.ts +29 -7
- package/dist/index.js +51 -6
- package/dist/index.js.map +1 -1
- package/dist/preact/index.cjs +795 -148
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.d.cts +4 -1
- package/dist/preact/index.d.ts +4 -1
- package/dist/preact/index.js +795 -146
- package/dist/preact/index.js.map +1 -1
- package/package.json +8 -8
package/dist/preact/index.js
CHANGED
|
@@ -5,77 +5,246 @@ var useAnnotationPlugin = () => usePlugin(AnnotationPlugin.id);
|
|
|
5
5
|
var useAnnotationCapability = () => useCapability(AnnotationPlugin.id);
|
|
6
6
|
|
|
7
7
|
// src/preact/components/annotations.tsx
|
|
8
|
-
import { PdfAnnotationSubtype } from "@embedpdf/models";
|
|
8
|
+
import { PdfAnnotationSubtype as PdfAnnotationSubtype2 } from "@embedpdf/models";
|
|
9
9
|
import { usePointerHandlers } from "@embedpdf/plugin-interaction-manager/preact";
|
|
10
10
|
import {
|
|
11
11
|
getAnnotationsByPageIndex,
|
|
12
12
|
getSelectedAnnotationByPageIndex
|
|
13
13
|
} from "@embedpdf/plugin-annotation";
|
|
14
|
-
import { useMemo, useState, useEffect } from "preact/hooks";
|
|
14
|
+
import { useMemo as useMemo2, useState as useState2, useEffect as useEffect2, useCallback } from "preact/hooks";
|
|
15
15
|
|
|
16
|
-
// src/preact/components/
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
16
|
+
// src/preact/components/annotation-container.tsx
|
|
17
|
+
import { useEffect, useRef, useState } from "preact/hooks";
|
|
18
|
+
import { restoreOffset } from "@embedpdf/models";
|
|
19
19
|
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
20
|
-
function
|
|
21
|
-
trackedAnnotation,
|
|
20
|
+
function AnnotationContainer({
|
|
22
21
|
scale,
|
|
23
|
-
isSelected = false,
|
|
24
22
|
pageIndex,
|
|
25
|
-
|
|
23
|
+
rotation,
|
|
24
|
+
trackedAnnotation,
|
|
25
|
+
children,
|
|
26
|
+
style,
|
|
27
|
+
outlineOffset = 1,
|
|
28
|
+
isSelected = false,
|
|
29
|
+
isDraggable = true,
|
|
30
|
+
isResizable = true,
|
|
31
|
+
computeResizePatch,
|
|
32
|
+
...props
|
|
26
33
|
}) {
|
|
27
34
|
const { provides: annotationProvides } = useAnnotationCapability();
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
const ref = useRef(null);
|
|
36
|
+
const [dragState, setDragState] = useState("idle");
|
|
37
|
+
const [resizeDirection, setResizeDirection] = useState(null);
|
|
38
|
+
const [startPos, setStartPos] = useState(null);
|
|
39
|
+
const [startRect, setStartRect] = useState(null);
|
|
40
|
+
const [currentRect, setCurrentRect] = useState(trackedAnnotation.object.rect);
|
|
41
|
+
const [previewObject, setPreviewObject] = useState(null);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
setCurrentRect(trackedAnnotation.object.rect);
|
|
44
|
+
setPreviewObject(null);
|
|
45
|
+
}, [trackedAnnotation]);
|
|
46
|
+
const handlePointerDown = (e) => {
|
|
47
|
+
if (!isSelected) return;
|
|
48
|
+
e.stopPropagation();
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
const target = e.target;
|
|
51
|
+
if (isResizable && target.classList.contains("resize-handle")) {
|
|
52
|
+
setDragState("resizing");
|
|
53
|
+
setResizeDirection(target.dataset.direction);
|
|
54
|
+
} else if (isDraggable) {
|
|
55
|
+
setDragState("dragging");
|
|
56
|
+
} else {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
setStartPos({ x: e.clientX, y: e.clientY });
|
|
60
|
+
setStartRect(currentRect);
|
|
61
|
+
ref.current?.setPointerCapture(e.pointerId);
|
|
62
|
+
};
|
|
63
|
+
const handlePointerMove = (e) => {
|
|
64
|
+
if (dragState === "idle" || !startPos || !startRect) return;
|
|
65
|
+
const dispDelta = { x: e.clientX - startPos.x, y: e.clientY - startPos.y };
|
|
66
|
+
const { x: dx, y: dy } = restoreOffset(dispDelta, rotation, scale);
|
|
67
|
+
let newOriginX = startRect.origin.x;
|
|
68
|
+
let newOriginY = startRect.origin.y;
|
|
69
|
+
let newWidth = startRect.size.width;
|
|
70
|
+
let newHeight = startRect.size.height;
|
|
71
|
+
if (dragState === "dragging") {
|
|
72
|
+
newOriginX += dx;
|
|
73
|
+
newOriginY += dy;
|
|
74
|
+
} else if (dragState === "resizing" && resizeDirection) {
|
|
75
|
+
if (resizeDirection.includes("right")) {
|
|
76
|
+
newWidth += dx;
|
|
77
|
+
} else if (resizeDirection.includes("left")) {
|
|
78
|
+
newOriginX += dx;
|
|
79
|
+
newWidth -= dx;
|
|
35
80
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
81
|
+
if (resizeDirection.includes("bottom")) {
|
|
82
|
+
newHeight += dy;
|
|
83
|
+
} else if (resizeDirection.includes("top")) {
|
|
84
|
+
newOriginY += dy;
|
|
85
|
+
newHeight -= dy;
|
|
86
|
+
}
|
|
87
|
+
if (newWidth < 1 || newHeight < 1) return;
|
|
88
|
+
}
|
|
89
|
+
const tentativeRect = {
|
|
90
|
+
origin: { x: newOriginX, y: newOriginY },
|
|
91
|
+
size: { width: newWidth, height: newHeight }
|
|
92
|
+
};
|
|
93
|
+
let previewPatch = { rect: tentativeRect };
|
|
94
|
+
if (computeResizePatch) {
|
|
95
|
+
const dir = dragState === "resizing" ? resizeDirection : "bottom-right";
|
|
96
|
+
if (dir) {
|
|
97
|
+
previewPatch = computeResizePatch(trackedAnnotation.object, tentativeRect, dir);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
setCurrentRect(previewPatch.rect || tentativeRect);
|
|
101
|
+
setPreviewObject(previewPatch);
|
|
102
|
+
};
|
|
103
|
+
const handlePointerUp = (e) => {
|
|
104
|
+
if (dragState === "idle") return;
|
|
105
|
+
const usedDirection = resizeDirection || "bottom-right";
|
|
106
|
+
setDragState("idle");
|
|
107
|
+
setResizeDirection(null);
|
|
108
|
+
ref.current?.releasePointerCapture(e.pointerId);
|
|
109
|
+
if (annotationProvides && trackedAnnotation) {
|
|
110
|
+
let patch = { rect: currentRect };
|
|
111
|
+
if (computeResizePatch && usedDirection) {
|
|
112
|
+
patch = computeResizePatch(trackedAnnotation.object, currentRect, usedDirection);
|
|
58
113
|
}
|
|
59
|
-
|
|
60
|
-
|
|
114
|
+
annotationProvides.updateAnnotation(pageIndex, trackedAnnotation.localId, patch);
|
|
115
|
+
}
|
|
116
|
+
setStartPos(null);
|
|
117
|
+
setStartRect(null);
|
|
118
|
+
setPreviewObject(null);
|
|
119
|
+
};
|
|
120
|
+
const currentObject = previewObject ? { ...trackedAnnotation.object, ...previewObject } : trackedAnnotation.object;
|
|
121
|
+
return /* @__PURE__ */ jsxs(
|
|
122
|
+
"div",
|
|
123
|
+
{
|
|
124
|
+
ref,
|
|
125
|
+
onPointerDown: handlePointerDown,
|
|
126
|
+
onPointerMove: handlePointerMove,
|
|
127
|
+
onPointerUp: handlePointerUp,
|
|
128
|
+
style: {
|
|
129
|
+
position: "absolute",
|
|
130
|
+
outline: isSelected ? "1px solid #007ACC" : "none",
|
|
131
|
+
outlineOffset: isSelected ? `${outlineOffset}px` : "0px",
|
|
132
|
+
left: `${currentRect.origin.x * scale}px`,
|
|
133
|
+
top: `${currentRect.origin.y * scale}px`,
|
|
134
|
+
width: `${currentRect.size.width * scale}px`,
|
|
135
|
+
height: `${currentRect.size.height * scale}px`,
|
|
136
|
+
pointerEvents: isSelected ? "auto" : "none",
|
|
137
|
+
cursor: isSelected && isDraggable ? "move" : "default",
|
|
138
|
+
...style
|
|
139
|
+
},
|
|
140
|
+
...props,
|
|
141
|
+
children: [
|
|
142
|
+
typeof children === "function" ? children(currentObject) : children,
|
|
143
|
+
isSelected && isResizable && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
144
|
+
/* @__PURE__ */ jsx(
|
|
145
|
+
"div",
|
|
146
|
+
{
|
|
147
|
+
className: "resize-handle",
|
|
148
|
+
"data-direction": "top-left",
|
|
149
|
+
style: {
|
|
150
|
+
position: "absolute",
|
|
151
|
+
top: -7 - outlineOffset,
|
|
152
|
+
left: -7 - outlineOffset,
|
|
153
|
+
width: 13,
|
|
154
|
+
height: 13,
|
|
155
|
+
background: "blue",
|
|
156
|
+
borderRadius: "50%",
|
|
157
|
+
cursor: rotation % 2 ? "nesw-resize" : "nwse-resize"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
),
|
|
161
|
+
/* @__PURE__ */ jsx(
|
|
162
|
+
"div",
|
|
163
|
+
{
|
|
164
|
+
className: "resize-handle",
|
|
165
|
+
"data-direction": "top-right",
|
|
166
|
+
style: {
|
|
167
|
+
position: "absolute",
|
|
168
|
+
top: -7 - outlineOffset,
|
|
169
|
+
right: -7 - outlineOffset,
|
|
170
|
+
width: 13,
|
|
171
|
+
height: 13,
|
|
172
|
+
background: "blue",
|
|
173
|
+
borderRadius: "50%",
|
|
174
|
+
cursor: rotation % 2 ? "nwse-resize" : "nesw-resize"
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
),
|
|
178
|
+
/* @__PURE__ */ jsx(
|
|
179
|
+
"div",
|
|
180
|
+
{
|
|
181
|
+
className: "resize-handle",
|
|
182
|
+
"data-direction": "bottom-left",
|
|
183
|
+
style: {
|
|
184
|
+
position: "absolute",
|
|
185
|
+
bottom: -7 - outlineOffset,
|
|
186
|
+
left: -7 - outlineOffset,
|
|
187
|
+
width: 13,
|
|
188
|
+
height: 13,
|
|
189
|
+
background: "blue",
|
|
190
|
+
borderRadius: "50%",
|
|
191
|
+
cursor: rotation % 2 ? "nwse-resize" : "nesw-resize"
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
),
|
|
195
|
+
/* @__PURE__ */ jsx(
|
|
196
|
+
"div",
|
|
197
|
+
{
|
|
198
|
+
className: "resize-handle",
|
|
199
|
+
"data-direction": "bottom-right",
|
|
200
|
+
style: {
|
|
201
|
+
position: "absolute",
|
|
202
|
+
bottom: -7 - outlineOffset,
|
|
203
|
+
right: -7 - outlineOffset,
|
|
204
|
+
width: 13,
|
|
205
|
+
height: 13,
|
|
206
|
+
background: "blue",
|
|
207
|
+
borderRadius: "50%",
|
|
208
|
+
cursor: rotation % 2 ? "nesw-resize" : "nwse-resize"
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
] })
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
);
|
|
61
216
|
}
|
|
62
217
|
|
|
63
218
|
// src/preact/components/text-markup/highlight.tsx
|
|
64
219
|
import { Fragment as Fragment2, jsx as jsx2 } from "preact/jsx-runtime";
|
|
65
|
-
function Highlight({
|
|
220
|
+
function Highlight({
|
|
221
|
+
color = "#FFFF00",
|
|
222
|
+
opacity = 0.5,
|
|
223
|
+
rects,
|
|
224
|
+
rect,
|
|
225
|
+
scale,
|
|
226
|
+
onClick,
|
|
227
|
+
style,
|
|
228
|
+
...props
|
|
229
|
+
}) {
|
|
66
230
|
return /* @__PURE__ */ jsx2(Fragment2, { children: rects.map((b, i) => /* @__PURE__ */ jsx2(
|
|
67
231
|
"div",
|
|
68
232
|
{
|
|
233
|
+
onMouseDown: onClick,
|
|
69
234
|
style: {
|
|
70
235
|
position: "absolute",
|
|
71
|
-
left: b.origin.x * scale,
|
|
72
|
-
top: b.origin.y * scale,
|
|
236
|
+
left: (rect ? b.origin.x - rect.origin.x : b.origin.x) * scale,
|
|
237
|
+
top: (rect ? b.origin.y - rect.origin.y : b.origin.y) * scale,
|
|
73
238
|
width: b.size.width * scale,
|
|
74
239
|
height: b.size.height * scale,
|
|
75
240
|
background: color,
|
|
76
241
|
opacity,
|
|
77
|
-
pointerEvents: "none"
|
|
78
|
-
|
|
242
|
+
pointerEvents: onClick ? "auto" : "none",
|
|
243
|
+
cursor: onClick ? "pointer" : "default",
|
|
244
|
+
zIndex: onClick ? 1 : null,
|
|
245
|
+
...style
|
|
246
|
+
},
|
|
247
|
+
...props
|
|
79
248
|
},
|
|
80
249
|
i
|
|
81
250
|
)) });
|
|
@@ -83,21 +252,49 @@ function Highlight({ color = "#FFFF00", opacity = 0.5, rects, scale }) {
|
|
|
83
252
|
|
|
84
253
|
// src/preact/components/text-markup/underline.tsx
|
|
85
254
|
import { Fragment as Fragment3, jsx as jsx3 } from "preact/jsx-runtime";
|
|
86
|
-
function Underline({
|
|
255
|
+
function Underline({
|
|
256
|
+
color = "#FFFF00",
|
|
257
|
+
opacity = 0.5,
|
|
258
|
+
rects,
|
|
259
|
+
rect,
|
|
260
|
+
scale,
|
|
261
|
+
onClick,
|
|
262
|
+
style,
|
|
263
|
+
...props
|
|
264
|
+
}) {
|
|
87
265
|
const thickness = 2 * scale;
|
|
88
266
|
return /* @__PURE__ */ jsx3(Fragment3, { children: rects.map((r, i) => /* @__PURE__ */ jsx3(
|
|
89
267
|
"div",
|
|
90
268
|
{
|
|
269
|
+
onMouseDown: onClick,
|
|
91
270
|
style: {
|
|
92
271
|
position: "absolute",
|
|
93
|
-
left: r.origin.x * scale,
|
|
94
|
-
top: (r.origin.y
|
|
272
|
+
left: (rect ? r.origin.x - rect.origin.x : r.origin.x) * scale,
|
|
273
|
+
top: (rect ? r.origin.y - rect.origin.y : r.origin.y) * scale,
|
|
95
274
|
width: r.size.width * scale,
|
|
96
|
-
height:
|
|
97
|
-
background:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
275
|
+
height: r.size.height * scale,
|
|
276
|
+
background: "transparent",
|
|
277
|
+
pointerEvents: onClick ? "auto" : "none",
|
|
278
|
+
cursor: onClick ? "pointer" : "default",
|
|
279
|
+
zIndex: onClick ? 1 : 0,
|
|
280
|
+
...style
|
|
281
|
+
},
|
|
282
|
+
...props,
|
|
283
|
+
children: /* @__PURE__ */ jsx3(
|
|
284
|
+
"div",
|
|
285
|
+
{
|
|
286
|
+
style: {
|
|
287
|
+
position: "absolute",
|
|
288
|
+
left: 0,
|
|
289
|
+
bottom: 0,
|
|
290
|
+
width: "100%",
|
|
291
|
+
height: thickness,
|
|
292
|
+
background: color,
|
|
293
|
+
opacity,
|
|
294
|
+
pointerEvents: "none"
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
)
|
|
101
298
|
},
|
|
102
299
|
i
|
|
103
300
|
)) });
|
|
@@ -105,21 +302,50 @@ function Underline({ color = "#FFFF00", opacity = 0.5, rects, scale }) {
|
|
|
105
302
|
|
|
106
303
|
// src/preact/components/text-markup/strikeout.tsx
|
|
107
304
|
import { Fragment as Fragment4, jsx as jsx4 } from "preact/jsx-runtime";
|
|
108
|
-
function Strikeout({
|
|
305
|
+
function Strikeout({
|
|
306
|
+
color = "#FFFF00",
|
|
307
|
+
opacity = 0.5,
|
|
308
|
+
rects,
|
|
309
|
+
rect,
|
|
310
|
+
scale,
|
|
311
|
+
onClick,
|
|
312
|
+
style,
|
|
313
|
+
...props
|
|
314
|
+
}) {
|
|
109
315
|
const thickness = 2 * scale;
|
|
110
316
|
return /* @__PURE__ */ jsx4(Fragment4, { children: rects.map((r, i) => /* @__PURE__ */ jsx4(
|
|
111
317
|
"div",
|
|
112
318
|
{
|
|
319
|
+
onMouseDown: onClick,
|
|
113
320
|
style: {
|
|
114
321
|
position: "absolute",
|
|
115
|
-
left: r.origin.x * scale,
|
|
116
|
-
top: (r.origin.y
|
|
322
|
+
left: (rect ? r.origin.x - rect.origin.x : r.origin.x) * scale,
|
|
323
|
+
top: (rect ? r.origin.y - rect.origin.y : r.origin.y) * scale,
|
|
117
324
|
width: r.size.width * scale,
|
|
118
|
-
height:
|
|
119
|
-
background:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
325
|
+
height: r.size.height * scale,
|
|
326
|
+
background: "transparent",
|
|
327
|
+
pointerEvents: onClick ? "auto" : "none",
|
|
328
|
+
cursor: onClick ? "pointer" : "default",
|
|
329
|
+
zIndex: onClick ? 1 : 0,
|
|
330
|
+
...style
|
|
331
|
+
},
|
|
332
|
+
...props,
|
|
333
|
+
children: /* @__PURE__ */ jsx4(
|
|
334
|
+
"div",
|
|
335
|
+
{
|
|
336
|
+
style: {
|
|
337
|
+
position: "absolute",
|
|
338
|
+
left: 0,
|
|
339
|
+
top: "50%",
|
|
340
|
+
width: "100%",
|
|
341
|
+
height: thickness,
|
|
342
|
+
background: color,
|
|
343
|
+
opacity,
|
|
344
|
+
transform: "translateY(-50%)",
|
|
345
|
+
pointerEvents: "none"
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
)
|
|
123
349
|
},
|
|
124
350
|
i
|
|
125
351
|
)) });
|
|
@@ -127,7 +353,16 @@ function Strikeout({ color = "#FFFF00", opacity = 0.5, rects, scale }) {
|
|
|
127
353
|
|
|
128
354
|
// src/preact/components/text-markup/squiggly.tsx
|
|
129
355
|
import { Fragment as Fragment5, jsx as jsx5 } from "preact/jsx-runtime";
|
|
130
|
-
function Squiggly({
|
|
356
|
+
function Squiggly({
|
|
357
|
+
color = "#FFFF00",
|
|
358
|
+
opacity = 0.5,
|
|
359
|
+
rects,
|
|
360
|
+
rect,
|
|
361
|
+
scale,
|
|
362
|
+
onClick,
|
|
363
|
+
style,
|
|
364
|
+
...props
|
|
365
|
+
}) {
|
|
131
366
|
const amplitude = 2 * scale;
|
|
132
367
|
const period = 6 * scale;
|
|
133
368
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${period}" height="${amplitude * 2}" viewBox="0 0 ${period} ${amplitude * 2}">
|
|
@@ -138,31 +373,162 @@ function Squiggly({ color = "#FFFF00", opacity = 0.5, rects, scale }) {
|
|
|
138
373
|
return /* @__PURE__ */ jsx5(Fragment5, { children: rects.map((r, i) => /* @__PURE__ */ jsx5(
|
|
139
374
|
"div",
|
|
140
375
|
{
|
|
376
|
+
onMouseDown: onClick,
|
|
141
377
|
style: {
|
|
142
378
|
position: "absolute",
|
|
143
|
-
left: r.origin.x * scale,
|
|
144
|
-
top: (r.origin.y
|
|
379
|
+
left: (rect ? r.origin.x - rect.origin.x : r.origin.x) * scale,
|
|
380
|
+
top: (rect ? r.origin.y - rect.origin.y : r.origin.y) * scale,
|
|
145
381
|
width: r.size.width * scale,
|
|
146
|
-
height:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
382
|
+
height: r.size.height * scale,
|
|
383
|
+
background: "transparent",
|
|
384
|
+
pointerEvents: onClick ? "auto" : "none",
|
|
385
|
+
cursor: onClick ? "pointer" : "default",
|
|
386
|
+
zIndex: onClick ? 1 : 0,
|
|
387
|
+
...style
|
|
388
|
+
},
|
|
389
|
+
...props,
|
|
390
|
+
children: /* @__PURE__ */ jsx5(
|
|
391
|
+
"div",
|
|
392
|
+
{
|
|
393
|
+
style: {
|
|
394
|
+
position: "absolute",
|
|
395
|
+
left: 0,
|
|
396
|
+
bottom: 0,
|
|
397
|
+
width: "100%",
|
|
398
|
+
height: amplitude * 2,
|
|
399
|
+
backgroundImage: svgDataUri,
|
|
400
|
+
backgroundRepeat: "repeat-x",
|
|
401
|
+
backgroundSize: `${period}px ${amplitude * 2}px`,
|
|
402
|
+
opacity,
|
|
403
|
+
pointerEvents: "none"
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
)
|
|
153
407
|
},
|
|
154
408
|
i
|
|
155
409
|
)) });
|
|
156
410
|
}
|
|
157
411
|
|
|
412
|
+
// src/preact/components/annotations/ink.tsx
|
|
413
|
+
import { useMemo } from "preact/hooks";
|
|
414
|
+
import { jsx as jsx6 } from "preact/jsx-runtime";
|
|
415
|
+
function Ink({
|
|
416
|
+
color = "#000000",
|
|
417
|
+
opacity = 1,
|
|
418
|
+
strokeWidth,
|
|
419
|
+
inkList,
|
|
420
|
+
rect,
|
|
421
|
+
scale,
|
|
422
|
+
onClick
|
|
423
|
+
}) {
|
|
424
|
+
const paths = useMemo(() => {
|
|
425
|
+
return inkList.map(({ points }) => {
|
|
426
|
+
let d = "";
|
|
427
|
+
points.forEach(({ x, y }, i) => {
|
|
428
|
+
const lx = x - rect.origin.x;
|
|
429
|
+
const ly = y - rect.origin.y;
|
|
430
|
+
d += (i === 0 ? "M" : "L") + lx + " " + ly + " ";
|
|
431
|
+
});
|
|
432
|
+
return d.trim();
|
|
433
|
+
});
|
|
434
|
+
}, [inkList, rect]);
|
|
435
|
+
const width = rect.size.width * scale;
|
|
436
|
+
const height = rect.size.height * scale;
|
|
437
|
+
return /* @__PURE__ */ jsx6(
|
|
438
|
+
"svg",
|
|
439
|
+
{
|
|
440
|
+
style: {
|
|
441
|
+
position: "absolute",
|
|
442
|
+
width,
|
|
443
|
+
height,
|
|
444
|
+
pointerEvents: "none",
|
|
445
|
+
zIndex: 2
|
|
446
|
+
},
|
|
447
|
+
width,
|
|
448
|
+
height,
|
|
449
|
+
viewBox: `0 0 ${rect.size.width} ${rect.size.height}`,
|
|
450
|
+
children: paths.map((d, i) => /* @__PURE__ */ jsx6(
|
|
451
|
+
"path",
|
|
452
|
+
{
|
|
453
|
+
d,
|
|
454
|
+
fill: "none",
|
|
455
|
+
stroke: color,
|
|
456
|
+
strokeWidth,
|
|
457
|
+
strokeLinecap: "round",
|
|
458
|
+
strokeLinejoin: "round",
|
|
459
|
+
opacity,
|
|
460
|
+
pointerEvents: "visibleStroke",
|
|
461
|
+
onMouseDown: onClick,
|
|
462
|
+
style: {
|
|
463
|
+
cursor: "pointer"
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
i
|
|
467
|
+
))
|
|
468
|
+
}
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
|
|
158
472
|
// src/preact/components/annotations.tsx
|
|
159
|
-
import {
|
|
160
|
-
|
|
473
|
+
import { useSelectionCapability } from "@embedpdf/plugin-selection/preact";
|
|
474
|
+
|
|
475
|
+
// src/shared/resize-ink.ts
|
|
476
|
+
import {
|
|
477
|
+
PdfAnnotationSubtype
|
|
478
|
+
} from "@embedpdf/models";
|
|
479
|
+
function resizeInkAnnotation(original, newRect, direction, uniform = false) {
|
|
480
|
+
if (original.type !== PdfAnnotationSubtype.INK) {
|
|
481
|
+
throw new Error("resizeInkAnnotation: original is not an ink annotation");
|
|
482
|
+
}
|
|
483
|
+
const oldRect = original.rect;
|
|
484
|
+
let scaleX = newRect.size.width / oldRect.size.width;
|
|
485
|
+
let scaleY = newRect.size.height / oldRect.size.height;
|
|
486
|
+
const minSize = 10;
|
|
487
|
+
if (newRect.size.width < minSize || newRect.size.height < minSize) {
|
|
488
|
+
scaleX = Math.max(scaleX, minSize / oldRect.size.width);
|
|
489
|
+
scaleY = Math.max(scaleY, minSize / oldRect.size.height);
|
|
490
|
+
newRect = {
|
|
491
|
+
origin: newRect.origin,
|
|
492
|
+
size: {
|
|
493
|
+
width: oldRect.size.width * scaleX,
|
|
494
|
+
height: oldRect.size.height * scaleY
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
if (uniform) {
|
|
499
|
+
const minScale = Math.min(scaleX, scaleY);
|
|
500
|
+
scaleX = minScale;
|
|
501
|
+
scaleY = minScale;
|
|
502
|
+
newRect.size = {
|
|
503
|
+
width: oldRect.size.width * minScale,
|
|
504
|
+
height: oldRect.size.height * minScale
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
const newInkList = original.inkList.map((stroke) => ({
|
|
508
|
+
points: stroke.points.map((p) => ({
|
|
509
|
+
x: newRect.origin.x + (p.x - oldRect.origin.x) * scaleX,
|
|
510
|
+
y: newRect.origin.y + (p.y - oldRect.origin.y) * scaleY
|
|
511
|
+
}))
|
|
512
|
+
}));
|
|
513
|
+
const avgScale = (scaleX + scaleY) / 2;
|
|
514
|
+
const newStrokeWidth = original.strokeWidth * avgScale;
|
|
515
|
+
return {
|
|
516
|
+
rect: newRect,
|
|
517
|
+
inkList: newInkList,
|
|
518
|
+
strokeWidth: newStrokeWidth
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// src/preact/components/annotations.tsx
|
|
523
|
+
import { Fragment as Fragment6, jsx as jsx7 } from "preact/jsx-runtime";
|
|
524
|
+
function Annotations(annotationsProps) {
|
|
525
|
+
const { pageIndex, scale } = annotationsProps;
|
|
161
526
|
const { provides: annotationProvides } = useAnnotationCapability();
|
|
162
|
-
const
|
|
527
|
+
const { provides: selectionProvides } = useSelectionCapability();
|
|
528
|
+
const [annotations, setAnnotations] = useState2([]);
|
|
163
529
|
const { register } = usePointerHandlers({ pageIndex });
|
|
164
|
-
const [selectionState, setSelectionState] =
|
|
165
|
-
|
|
530
|
+
const [selectionState, setSelectionState] = useState2(null);
|
|
531
|
+
useEffect2(() => {
|
|
166
532
|
if (annotationProvides) {
|
|
167
533
|
annotationProvides.onStateChange((state) => {
|
|
168
534
|
setAnnotations(getAnnotationsByPageIndex(state, pageIndex));
|
|
@@ -170,7 +536,7 @@ function Annotations({ pageIndex, scale }) {
|
|
|
170
536
|
});
|
|
171
537
|
}
|
|
172
538
|
}, [annotationProvides]);
|
|
173
|
-
const handlers =
|
|
539
|
+
const handlers = useMemo2(
|
|
174
540
|
() => ({
|
|
175
541
|
onPointerDown: (_, pe) => {
|
|
176
542
|
if (pe.target === pe.currentTarget && annotationProvides) {
|
|
@@ -180,87 +546,137 @@ function Annotations({ pageIndex, scale }) {
|
|
|
180
546
|
}),
|
|
181
547
|
[annotationProvides]
|
|
182
548
|
);
|
|
183
|
-
|
|
549
|
+
const handleClick = useCallback(
|
|
550
|
+
(e, annotation) => {
|
|
551
|
+
e.stopPropagation();
|
|
552
|
+
if (annotationProvides && selectionProvides) {
|
|
553
|
+
annotationProvides.selectAnnotation(pageIndex, annotation.localId);
|
|
554
|
+
selectionProvides.clear();
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
[annotationProvides, selectionProvides, pageIndex]
|
|
558
|
+
);
|
|
559
|
+
useEffect2(() => {
|
|
184
560
|
return register(handlers);
|
|
185
561
|
}, [register, handlers]);
|
|
186
|
-
return /* @__PURE__ */
|
|
562
|
+
return /* @__PURE__ */ jsx7(Fragment6, { children: annotations.map((annotation) => {
|
|
187
563
|
const isSelected = selectionState?.localId === annotation.localId;
|
|
188
564
|
switch (annotation.object.type) {
|
|
189
|
-
case
|
|
190
|
-
return /* @__PURE__ */
|
|
191
|
-
|
|
565
|
+
case PdfAnnotationSubtype2.UNDERLINE:
|
|
566
|
+
return /* @__PURE__ */ jsx7(
|
|
567
|
+
AnnotationContainer,
|
|
192
568
|
{
|
|
193
569
|
trackedAnnotation: annotation,
|
|
194
|
-
scale,
|
|
195
570
|
isSelected,
|
|
196
|
-
|
|
197
|
-
|
|
571
|
+
isDraggable: false,
|
|
572
|
+
isResizable: false,
|
|
573
|
+
style: { mixBlendMode: "multiply" },
|
|
574
|
+
...annotationsProps,
|
|
575
|
+
children: /* @__PURE__ */ jsx7(
|
|
198
576
|
Underline,
|
|
199
577
|
{
|
|
578
|
+
rect: annotation.object.rect,
|
|
200
579
|
color: annotation.object.color,
|
|
201
580
|
opacity: annotation.object.opacity,
|
|
202
581
|
rects: annotation.object.segmentRects,
|
|
203
|
-
scale
|
|
582
|
+
scale,
|
|
583
|
+
onClick: (e) => handleClick(e, annotation)
|
|
204
584
|
}
|
|
205
585
|
)
|
|
206
586
|
},
|
|
207
587
|
annotation.localId
|
|
208
588
|
);
|
|
209
|
-
case
|
|
210
|
-
return /* @__PURE__ */
|
|
211
|
-
|
|
589
|
+
case PdfAnnotationSubtype2.STRIKEOUT:
|
|
590
|
+
return /* @__PURE__ */ jsx7(
|
|
591
|
+
AnnotationContainer,
|
|
212
592
|
{
|
|
213
593
|
trackedAnnotation: annotation,
|
|
214
|
-
scale,
|
|
215
594
|
isSelected,
|
|
216
|
-
|
|
217
|
-
|
|
595
|
+
isDraggable: false,
|
|
596
|
+
isResizable: false,
|
|
597
|
+
style: { mixBlendMode: "multiply" },
|
|
598
|
+
...annotationsProps,
|
|
599
|
+
children: /* @__PURE__ */ jsx7(
|
|
218
600
|
Strikeout,
|
|
219
601
|
{
|
|
602
|
+
rect: annotation.object.rect,
|
|
220
603
|
color: annotation.object.color,
|
|
221
604
|
opacity: annotation.object.opacity,
|
|
222
605
|
rects: annotation.object.segmentRects,
|
|
223
|
-
scale
|
|
606
|
+
scale,
|
|
607
|
+
onClick: (e) => handleClick(e, annotation)
|
|
224
608
|
}
|
|
225
609
|
)
|
|
226
610
|
},
|
|
227
611
|
annotation.localId
|
|
228
612
|
);
|
|
229
|
-
case
|
|
230
|
-
return /* @__PURE__ */
|
|
231
|
-
|
|
613
|
+
case PdfAnnotationSubtype2.SQUIGGLY:
|
|
614
|
+
return /* @__PURE__ */ jsx7(
|
|
615
|
+
AnnotationContainer,
|
|
232
616
|
{
|
|
233
617
|
trackedAnnotation: annotation,
|
|
234
|
-
scale,
|
|
235
618
|
isSelected,
|
|
236
|
-
|
|
237
|
-
|
|
619
|
+
isDraggable: false,
|
|
620
|
+
isResizable: false,
|
|
621
|
+
style: { mixBlendMode: "multiply" },
|
|
622
|
+
...annotationsProps,
|
|
623
|
+
children: /* @__PURE__ */ jsx7(
|
|
238
624
|
Squiggly,
|
|
239
625
|
{
|
|
240
626
|
color: annotation.object.color,
|
|
241
627
|
opacity: annotation.object.opacity,
|
|
242
628
|
rects: annotation.object.segmentRects,
|
|
243
|
-
|
|
629
|
+
rect: annotation.object.rect,
|
|
630
|
+
scale,
|
|
631
|
+
onClick: (e) => handleClick(e, annotation)
|
|
244
632
|
}
|
|
245
633
|
)
|
|
246
634
|
},
|
|
247
635
|
annotation.localId
|
|
248
636
|
);
|
|
249
|
-
case
|
|
250
|
-
return /* @__PURE__ */
|
|
251
|
-
|
|
637
|
+
case PdfAnnotationSubtype2.HIGHLIGHT:
|
|
638
|
+
return /* @__PURE__ */ jsx7(
|
|
639
|
+
AnnotationContainer,
|
|
252
640
|
{
|
|
253
641
|
trackedAnnotation: annotation,
|
|
254
|
-
scale,
|
|
255
642
|
isSelected,
|
|
256
|
-
|
|
257
|
-
|
|
643
|
+
isDraggable: false,
|
|
644
|
+
isResizable: false,
|
|
645
|
+
style: { mixBlendMode: "multiply" },
|
|
646
|
+
...annotationsProps,
|
|
647
|
+
children: /* @__PURE__ */ jsx7(
|
|
258
648
|
Highlight,
|
|
259
649
|
{
|
|
260
650
|
color: annotation.object.color,
|
|
261
651
|
opacity: annotation.object.opacity,
|
|
262
652
|
rects: annotation.object.segmentRects,
|
|
263
|
-
scale
|
|
653
|
+
scale,
|
|
654
|
+
rect: annotation.object.rect,
|
|
655
|
+
onClick: (e) => handleClick(e, annotation)
|
|
656
|
+
}
|
|
657
|
+
)
|
|
658
|
+
},
|
|
659
|
+
annotation.localId
|
|
660
|
+
);
|
|
661
|
+
case PdfAnnotationSubtype2.INK:
|
|
662
|
+
return /* @__PURE__ */ jsx7(
|
|
663
|
+
AnnotationContainer,
|
|
664
|
+
{
|
|
665
|
+
isSelected,
|
|
666
|
+
trackedAnnotation: annotation,
|
|
667
|
+
outlineOffset: 6,
|
|
668
|
+
computeResizePatch: resizeInkAnnotation,
|
|
669
|
+
...annotationsProps,
|
|
670
|
+
children: (obj) => /* @__PURE__ */ jsx7(
|
|
671
|
+
Ink,
|
|
672
|
+
{
|
|
673
|
+
color: obj.color,
|
|
674
|
+
opacity: obj.opacity,
|
|
675
|
+
strokeWidth: obj.strokeWidth,
|
|
676
|
+
inkList: obj.inkList,
|
|
677
|
+
rect: obj.rect,
|
|
678
|
+
scale,
|
|
679
|
+
onClick: (e) => handleClick(e, annotation)
|
|
264
680
|
}
|
|
265
681
|
)
|
|
266
682
|
},
|
|
@@ -273,66 +689,113 @@ function Annotations({ pageIndex, scale }) {
|
|
|
273
689
|
}
|
|
274
690
|
|
|
275
691
|
// src/preact/components/text-markup.tsx
|
|
276
|
-
import { PdfAnnotationSubtype as
|
|
692
|
+
import { PdfAnnotationSubtype as PdfAnnotationSubtype3 } from "@embedpdf/models";
|
|
277
693
|
import { useSelectionCapability as useSelectionCapability2 } from "@embedpdf/plugin-selection/preact";
|
|
278
|
-
import { useEffect as
|
|
279
|
-
import { jsx as
|
|
694
|
+
import { useEffect as useEffect3, useState as useState3 } from "preact/hooks";
|
|
695
|
+
import { jsx as jsx8 } from "preact/jsx-runtime";
|
|
280
696
|
function TextMarkup({ pageIndex, scale }) {
|
|
281
697
|
const { provides: selectionProvides } = useSelectionCapability2();
|
|
282
698
|
const { provides: annotationProvides } = useAnnotationCapability();
|
|
283
|
-
const [rects, setRects] =
|
|
284
|
-
const [
|
|
285
|
-
|
|
699
|
+
const [rects, setRects] = useState3([]);
|
|
700
|
+
const [boundingRect, setBoundingRect] = useState3(null);
|
|
701
|
+
const [activeTool, setActiveTool] = useState3({ mode: null, defaults: null });
|
|
702
|
+
useEffect3(() => {
|
|
286
703
|
if (!selectionProvides) return;
|
|
287
704
|
const off = selectionProvides.onSelectionChange(() => {
|
|
288
705
|
setRects(selectionProvides.getHighlightRectsForPage(pageIndex));
|
|
706
|
+
setBoundingRect(selectionProvides.getBoundingRectForPage(pageIndex));
|
|
289
707
|
});
|
|
290
708
|
return off;
|
|
291
709
|
}, [selectionProvides, pageIndex]);
|
|
292
|
-
|
|
710
|
+
useEffect3(() => {
|
|
293
711
|
if (!annotationProvides) return;
|
|
294
712
|
const off = annotationProvides.onActiveToolChange(setActiveTool);
|
|
295
713
|
return off;
|
|
296
714
|
}, [annotationProvides]);
|
|
715
|
+
if (!boundingRect) return null;
|
|
297
716
|
switch (activeTool.mode) {
|
|
298
|
-
case
|
|
299
|
-
return /* @__PURE__ */
|
|
300
|
-
|
|
717
|
+
case PdfAnnotationSubtype3.UNDERLINE:
|
|
718
|
+
return /* @__PURE__ */ jsx8(
|
|
719
|
+
"div",
|
|
301
720
|
{
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
721
|
+
style: {
|
|
722
|
+
mixBlendMode: "multiply",
|
|
723
|
+
pointerEvents: "none",
|
|
724
|
+
position: "absolute",
|
|
725
|
+
inset: 0
|
|
726
|
+
},
|
|
727
|
+
children: /* @__PURE__ */ jsx8(
|
|
728
|
+
Underline,
|
|
729
|
+
{
|
|
730
|
+
color: activeTool.defaults?.color,
|
|
731
|
+
opacity: activeTool.defaults?.opacity,
|
|
732
|
+
rects,
|
|
733
|
+
scale
|
|
734
|
+
}
|
|
735
|
+
)
|
|
306
736
|
}
|
|
307
737
|
);
|
|
308
|
-
case
|
|
309
|
-
return /* @__PURE__ */
|
|
310
|
-
|
|
738
|
+
case PdfAnnotationSubtype3.HIGHLIGHT:
|
|
739
|
+
return /* @__PURE__ */ jsx8(
|
|
740
|
+
"div",
|
|
311
741
|
{
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
742
|
+
style: {
|
|
743
|
+
mixBlendMode: "multiply",
|
|
744
|
+
pointerEvents: "none",
|
|
745
|
+
position: "absolute",
|
|
746
|
+
inset: 0
|
|
747
|
+
},
|
|
748
|
+
children: /* @__PURE__ */ jsx8(
|
|
749
|
+
Highlight,
|
|
750
|
+
{
|
|
751
|
+
color: activeTool.defaults?.color,
|
|
752
|
+
opacity: activeTool.defaults?.opacity,
|
|
753
|
+
rects,
|
|
754
|
+
scale
|
|
755
|
+
}
|
|
756
|
+
)
|
|
316
757
|
}
|
|
317
758
|
);
|
|
318
|
-
case
|
|
319
|
-
return /* @__PURE__ */
|
|
320
|
-
|
|
759
|
+
case PdfAnnotationSubtype3.STRIKEOUT:
|
|
760
|
+
return /* @__PURE__ */ jsx8(
|
|
761
|
+
"div",
|
|
321
762
|
{
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
763
|
+
style: {
|
|
764
|
+
mixBlendMode: "multiply",
|
|
765
|
+
pointerEvents: "none",
|
|
766
|
+
position: "absolute",
|
|
767
|
+
inset: 0
|
|
768
|
+
},
|
|
769
|
+
children: /* @__PURE__ */ jsx8(
|
|
770
|
+
Strikeout,
|
|
771
|
+
{
|
|
772
|
+
color: activeTool.defaults?.color,
|
|
773
|
+
opacity: activeTool.defaults?.opacity,
|
|
774
|
+
rects,
|
|
775
|
+
scale
|
|
776
|
+
}
|
|
777
|
+
)
|
|
326
778
|
}
|
|
327
779
|
);
|
|
328
|
-
case
|
|
329
|
-
return /* @__PURE__ */
|
|
330
|
-
|
|
780
|
+
case PdfAnnotationSubtype3.SQUIGGLY:
|
|
781
|
+
return /* @__PURE__ */ jsx8(
|
|
782
|
+
"div",
|
|
331
783
|
{
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
784
|
+
style: {
|
|
785
|
+
mixBlendMode: "multiply",
|
|
786
|
+
pointerEvents: "none",
|
|
787
|
+
position: "absolute",
|
|
788
|
+
inset: 0
|
|
789
|
+
},
|
|
790
|
+
children: /* @__PURE__ */ jsx8(
|
|
791
|
+
Squiggly,
|
|
792
|
+
{
|
|
793
|
+
color: activeTool.defaults?.color,
|
|
794
|
+
opacity: activeTool.defaults?.opacity,
|
|
795
|
+
rects,
|
|
796
|
+
scale
|
|
797
|
+
}
|
|
798
|
+
)
|
|
336
799
|
}
|
|
337
800
|
);
|
|
338
801
|
default:
|
|
@@ -340,9 +803,194 @@ function TextMarkup({ pageIndex, scale }) {
|
|
|
340
803
|
}
|
|
341
804
|
}
|
|
342
805
|
|
|
806
|
+
// src/preact/components/annotations/ink-paint.tsx
|
|
807
|
+
import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef2, useState as useState4 } from "preact/hooks";
|
|
808
|
+
import { usePointerHandlers as usePointerHandlers2 } from "@embedpdf/plugin-interaction-manager/preact";
|
|
809
|
+
import { PdfAnnotationSubtype as PdfAnnotationSubtype4 } from "@embedpdf/models";
|
|
810
|
+
import { jsx as jsx9 } from "preact/jsx-runtime";
|
|
811
|
+
var MAX_STROKE_WIDTH = 30;
|
|
812
|
+
var InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
|
|
813
|
+
const { provides: annotationProvides } = useAnnotationCapability();
|
|
814
|
+
const [activeTool, setActiveTool] = useState4({ mode: null, defaults: null });
|
|
815
|
+
useEffect4(() => {
|
|
816
|
+
if (!annotationProvides) return;
|
|
817
|
+
const off = annotationProvides.onActiveToolChange(setActiveTool);
|
|
818
|
+
return off;
|
|
819
|
+
}, [annotationProvides]);
|
|
820
|
+
if (activeTool.mode !== PdfAnnotationSubtype4.INK) return null;
|
|
821
|
+
const toolColor = activeTool.defaults?.color ?? "#000000";
|
|
822
|
+
const toolOpacity = activeTool.defaults?.opacity ?? 1;
|
|
823
|
+
const toolStrokeWidth = activeTool.defaults?.strokeWidth ?? 2;
|
|
824
|
+
const { register } = usePointerHandlers2({ modeId: "ink", pageIndex });
|
|
825
|
+
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
|
|
826
|
+
const [currentStrokes, setCurrentStrokes] = useState4([]);
|
|
827
|
+
const [isDrawing, setIsDrawing] = useState4(false);
|
|
828
|
+
const timerRef = useRef2(null);
|
|
829
|
+
const pageWidthPDF = pageWidth / scale;
|
|
830
|
+
const pageHeightPDF = pageHeight / scale;
|
|
831
|
+
const handlers = useMemo3(
|
|
832
|
+
() => ({
|
|
833
|
+
onPointerDown: (pos, evt) => {
|
|
834
|
+
const curX = clamp(pos.x, 0, pageWidthPDF);
|
|
835
|
+
const curY = clamp(pos.y, 0, pageHeightPDF);
|
|
836
|
+
setIsDrawing(true);
|
|
837
|
+
if (timerRef.current) {
|
|
838
|
+
clearTimeout(timerRef.current);
|
|
839
|
+
timerRef.current = null;
|
|
840
|
+
setCurrentStrokes((prev) => [...prev, { points: [{ x: curX, y: curY }] }]);
|
|
841
|
+
} else {
|
|
842
|
+
setCurrentStrokes([{ points: [{ x: curX, y: curY }] }]);
|
|
843
|
+
}
|
|
844
|
+
evt.target?.setPointerCapture?.(evt.pointerId);
|
|
845
|
+
},
|
|
846
|
+
onPointerMove: (pos) => {
|
|
847
|
+
if (!isDrawing) return;
|
|
848
|
+
const curX = clamp(pos.x, 0, pageWidthPDF);
|
|
849
|
+
const curY = clamp(pos.y, 0, pageHeightPDF);
|
|
850
|
+
setCurrentStrokes((prev) => {
|
|
851
|
+
if (!prev.length) return prev;
|
|
852
|
+
const last = prev[prev.length - 1];
|
|
853
|
+
const newLast = { points: [...last.points, { x: curX, y: curY }] };
|
|
854
|
+
return [...prev.slice(0, -1), newLast];
|
|
855
|
+
});
|
|
856
|
+
},
|
|
857
|
+
onPointerUp: (_, evt) => {
|
|
858
|
+
setIsDrawing(false);
|
|
859
|
+
evt.target?.releasePointerCapture?.(evt.pointerId);
|
|
860
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
861
|
+
timerRef.current = setTimeout(() => {
|
|
862
|
+
if (currentStrokes.length && annotationProvides) {
|
|
863
|
+
const allPoints2 = currentStrokes.flatMap((s) => s.points);
|
|
864
|
+
if (!allPoints2.length) return;
|
|
865
|
+
const minX2 = Math.min(...allPoints2.map((p) => p.x));
|
|
866
|
+
const minY2 = Math.min(...allPoints2.map((p) => p.y));
|
|
867
|
+
const maxX2 = Math.max(...allPoints2.map((p) => p.x));
|
|
868
|
+
const maxY2 = Math.max(...allPoints2.map((p) => p.y));
|
|
869
|
+
const halfStroke2 = MAX_STROKE_WIDTH / 2;
|
|
870
|
+
const rectMinX = minX2 - halfStroke2;
|
|
871
|
+
const rectMinY = minY2 - halfStroke2;
|
|
872
|
+
const rectMaxX = maxX2 + halfStroke2;
|
|
873
|
+
const rectMaxY = maxY2 + halfStroke2;
|
|
874
|
+
if (rectMaxX - rectMinX < 1 || rectMaxY - rectMinY < 1) return;
|
|
875
|
+
const rect = {
|
|
876
|
+
origin: { x: rectMinX, y: rectMinY },
|
|
877
|
+
size: { width: rectMaxX - rectMinX, height: rectMaxY - rectMinY }
|
|
878
|
+
};
|
|
879
|
+
const anno = {
|
|
880
|
+
type: PdfAnnotationSubtype4.INK,
|
|
881
|
+
rect,
|
|
882
|
+
inkList: currentStrokes,
|
|
883
|
+
color: toolColor,
|
|
884
|
+
opacity: toolOpacity,
|
|
885
|
+
strokeWidth: toolStrokeWidth,
|
|
886
|
+
pageIndex,
|
|
887
|
+
id: Date.now() + Math.random()
|
|
888
|
+
};
|
|
889
|
+
annotationProvides.createAnnotation(pageIndex, anno);
|
|
890
|
+
annotationProvides.setAnnotationMode(null);
|
|
891
|
+
annotationProvides.selectAnnotation(pageIndex, anno.id);
|
|
892
|
+
}
|
|
893
|
+
setCurrentStrokes([]);
|
|
894
|
+
timerRef.current = null;
|
|
895
|
+
}, 3e3);
|
|
896
|
+
},
|
|
897
|
+
onPointerCancel: (_, evt) => {
|
|
898
|
+
setIsDrawing(false);
|
|
899
|
+
evt.target?.releasePointerCapture?.(evt.pointerId);
|
|
900
|
+
setCurrentStrokes([]);
|
|
901
|
+
if (timerRef.current) {
|
|
902
|
+
clearTimeout(timerRef.current);
|
|
903
|
+
timerRef.current = null;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}),
|
|
907
|
+
[
|
|
908
|
+
pageWidthPDF,
|
|
909
|
+
pageHeightPDF,
|
|
910
|
+
currentStrokes,
|
|
911
|
+
annotationProvides,
|
|
912
|
+
pageIndex,
|
|
913
|
+
toolColor,
|
|
914
|
+
toolOpacity,
|
|
915
|
+
toolStrokeWidth,
|
|
916
|
+
isDrawing
|
|
917
|
+
]
|
|
918
|
+
);
|
|
919
|
+
useEffect4(() => {
|
|
920
|
+
if (!register) return;
|
|
921
|
+
return register(handlers);
|
|
922
|
+
}, [register, handlers]);
|
|
923
|
+
useEffect4(() => {
|
|
924
|
+
return () => {
|
|
925
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
926
|
+
};
|
|
927
|
+
}, []);
|
|
928
|
+
if (!currentStrokes.length) return null;
|
|
929
|
+
const allPoints = currentStrokes.flatMap((s) => s.points);
|
|
930
|
+
if (!allPoints.length) return null;
|
|
931
|
+
const minX = Math.min(...allPoints.map((p) => p.x));
|
|
932
|
+
const minY = Math.min(...allPoints.map((p) => p.y));
|
|
933
|
+
const maxX = Math.max(...allPoints.map((p) => p.x));
|
|
934
|
+
const maxY = Math.max(...allPoints.map((p) => p.y));
|
|
935
|
+
const halfStroke = MAX_STROKE_WIDTH / 2;
|
|
936
|
+
const svgMinX = minX - halfStroke;
|
|
937
|
+
const svgMinY = minY - halfStroke;
|
|
938
|
+
const svgMaxX = maxX + halfStroke;
|
|
939
|
+
const svgMaxY = maxY + halfStroke;
|
|
940
|
+
const dw = svgMaxX - svgMinX;
|
|
941
|
+
const dh = svgMaxY - svgMinY;
|
|
942
|
+
const paths = currentStrokes.map(({ points }) => {
|
|
943
|
+
let d = "";
|
|
944
|
+
points.forEach(({ x, y }, i) => {
|
|
945
|
+
const lx = x - svgMinX;
|
|
946
|
+
const ly = y - svgMinY;
|
|
947
|
+
d += (i === 0 ? "M" : "L") + lx + " " + ly + " ";
|
|
948
|
+
});
|
|
949
|
+
return d.trim();
|
|
950
|
+
});
|
|
951
|
+
return /* @__PURE__ */ jsx9(
|
|
952
|
+
"svg",
|
|
953
|
+
{
|
|
954
|
+
style: {
|
|
955
|
+
position: "absolute",
|
|
956
|
+
left: svgMinX * scale,
|
|
957
|
+
top: svgMinY * scale,
|
|
958
|
+
width: dw * scale,
|
|
959
|
+
height: dh * scale,
|
|
960
|
+
pointerEvents: "none",
|
|
961
|
+
zIndex: 2
|
|
962
|
+
},
|
|
963
|
+
width: dw * scale,
|
|
964
|
+
height: dh * scale,
|
|
965
|
+
viewBox: `0 0 ${dw} ${dh}`,
|
|
966
|
+
children: paths.map((d, i) => /* @__PURE__ */ jsx9(
|
|
967
|
+
"path",
|
|
968
|
+
{
|
|
969
|
+
d,
|
|
970
|
+
fill: "none",
|
|
971
|
+
stroke: toolColor,
|
|
972
|
+
strokeWidth: toolStrokeWidth,
|
|
973
|
+
strokeLinecap: "round",
|
|
974
|
+
strokeLinejoin: "round",
|
|
975
|
+
opacity: toolOpacity
|
|
976
|
+
},
|
|
977
|
+
i
|
|
978
|
+
))
|
|
979
|
+
}
|
|
980
|
+
);
|
|
981
|
+
};
|
|
982
|
+
|
|
343
983
|
// src/preact/components/annotation-layer.tsx
|
|
344
|
-
import { jsx as
|
|
345
|
-
function AnnotationLayer({
|
|
984
|
+
import { jsx as jsx10, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
985
|
+
function AnnotationLayer({
|
|
986
|
+
pageIndex,
|
|
987
|
+
scale,
|
|
988
|
+
pageWidth,
|
|
989
|
+
pageHeight,
|
|
990
|
+
rotation,
|
|
991
|
+
style,
|
|
992
|
+
...props
|
|
993
|
+
}) {
|
|
346
994
|
return /* @__PURE__ */ jsxs2(
|
|
347
995
|
"div",
|
|
348
996
|
{
|
|
@@ -351,8 +999,9 @@ function AnnotationLayer({ pageIndex, scale, style, ...props }) {
|
|
|
351
999
|
},
|
|
352
1000
|
...props,
|
|
353
1001
|
children: [
|
|
354
|
-
/* @__PURE__ */
|
|
355
|
-
/* @__PURE__ */
|
|
1002
|
+
/* @__PURE__ */ jsx10(Annotations, { pageIndex, scale, rotation }),
|
|
1003
|
+
/* @__PURE__ */ jsx10(TextMarkup, { pageIndex, scale }),
|
|
1004
|
+
/* @__PURE__ */ jsx10(InkPaint, { pageIndex, scale, pageWidth, pageHeight })
|
|
356
1005
|
]
|
|
357
1006
|
}
|
|
358
1007
|
);
|