pdfjs-annotation-extension-for-react 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +338 -0
- package/dist/__vite-browser-external-BcPniuRQ.cjs +1 -0
- package/dist/__vite-browser-external-DYxpcVy9.js +4 -0
- package/dist/index-ByK1C9Ha.cjs +1 -0
- package/dist/index-Dwr47WtL.js +230 -0
- package/dist/index.cjs.js +425 -0
- package/dist/index.d.ts +439 -0
- package/dist/index.es.js +81540 -0
- package/dist/pdfjs-annotation-extension-for-react.css +1 -0
- package/package.json +119 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Laomai<codefee@foxmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# pdfjs-annotation-extension-for-react
|
|
2
|
+
|
|
3
|
+
A lightweight, extensible React PDF viewer and annotator built on top of PDF.js, designed for enterprise-grade document reading and annotation scenarios.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/pdfjs-annotation-extension-for-react)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
## ✨ Features
|
|
9
|
+
|
|
10
|
+
- 📄 High-fidelity PDF rendering based on PDF.js
|
|
11
|
+
- ✍️ Rich annotation system
|
|
12
|
+
- Highlight, drawing, shapes, text notes
|
|
13
|
+
- Signatures (draw / enter / upload)
|
|
14
|
+
- Stamps with editor support
|
|
15
|
+
- Edit native PDF annotations directly
|
|
16
|
+
- 🎨 Theme system based on Radix UI Themes
|
|
17
|
+
- 🌍 Internationalization (zh-CN, en-US)
|
|
18
|
+
- 🧩 Highly customizable UI
|
|
19
|
+
- Toolbar / Sidebar / Actions fully overridable
|
|
20
|
+
- 🏢 Enterprise-friendly configuration
|
|
21
|
+
- `defaultOptions` supports DeepPartial + Deep Merge
|
|
22
|
+
- 💾 Export
|
|
23
|
+
- Export annotations to PDF
|
|
24
|
+
- Export annotations to Excel
|
|
25
|
+
- 🧠 Designed for extensibility
|
|
26
|
+
- Clean context & extension architecture
|
|
27
|
+
|
|
28
|
+
## Online Demo
|
|
29
|
+
|
|
30
|
+
[](https://laomai-codefee.github.io/pdfjs-annotation-extension-for-react-demo/)
|
|
31
|
+
|
|
32
|
+
## 📦 Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install pdfjs-annotation-extension-for-react
|
|
36
|
+
or
|
|
37
|
+
yarn add pdfjs-annotation-extension-for-react
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
# 🚀 Quick Start
|
|
41
|
+
|
|
42
|
+
## Basic PDF Viewer
|
|
43
|
+
|
|
44
|
+
```jsx
|
|
45
|
+
import { PdfViewer } from 'pdfjs-annotation-extension-for-react'
|
|
46
|
+
import 'pdfjs-annotation-extension-for-react/style'
|
|
47
|
+
|
|
48
|
+
export default function App() {
|
|
49
|
+
return (
|
|
50
|
+
<PdfViewer
|
|
51
|
+
title="PDF Viewer"
|
|
52
|
+
url="https://example.com/sample.pdf"
|
|
53
|
+
layoutStyle={{ width: '100vw', height: '100vh' }}
|
|
54
|
+
/>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## PDF Annotator
|
|
60
|
+
|
|
61
|
+
```jsx
|
|
62
|
+
import { PdfAnnotator } from 'pdfjs-annotation-extension-for-react'
|
|
63
|
+
import 'pdfjs-annotation-extension-for-react/style'
|
|
64
|
+
|
|
65
|
+
export default function App() {
|
|
66
|
+
return (
|
|
67
|
+
<PdfAnnotator
|
|
68
|
+
title="PDF Annotator"
|
|
69
|
+
url="https://example.com/sample.pdf"
|
|
70
|
+
user={{ id: 'u1', name: 'Alice' }}
|
|
71
|
+
onSave={(annotations) => {
|
|
72
|
+
console.log('Saved annotations:', annotations)
|
|
73
|
+
}}
|
|
74
|
+
/>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
# 🧩 Components
|
|
80
|
+
|
|
81
|
+
## 📄 PdfViewer
|
|
82
|
+
|
|
83
|
+
A lightweight PDF viewer with toolbar, sidebar, actions and extensible UI slots.
|
|
84
|
+
|
|
85
|
+
### Props
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
| Prop | Type | Default | Description |
|
|
89
|
+
| -------------------- | -------------------------------- | ------------------------------------- | ----------------------- |
|
|
90
|
+
| `theme` | Radix Theme Color | `'violet'` | Viewer theme color |
|
|
91
|
+
| `title` | `ReactNode` | - | Page title |
|
|
92
|
+
| `url` | `string | URL` | **required** | PDF file URL |
|
|
93
|
+
| `locale` | `'zh-CN' | 'en-US'` | `'zh-CN'` | UI language |
|
|
94
|
+
| `initialScale` | `PdfScale` | `'auto'` | Initial zoom |
|
|
95
|
+
| `layoutStyle` | `CSSProperties` | `{ width: '100vw', height: '100vh' }` | Container style |
|
|
96
|
+
| `isSidebarCollapsed` | `boolean` | `true` | Sidebar collapsed state |
|
|
97
|
+
| `showSidebarTrigger` | `boolean` | `false` | Show sidebar toggle |
|
|
98
|
+
| `showTextLayer` | `boolean` | `true` | Enable text selection |
|
|
99
|
+
| `actions` | `ReactNode | (ctx) => ReactNode` | - | Custom action area |
|
|
100
|
+
| `sidebar` | `ReactNode | (ctx) => ReactNode` | - | Custom sidebar |
|
|
101
|
+
| `toolbar` | `ReactNode | (ctx) => ReactNode` | ZoomTool | Custom toolbar |
|
|
102
|
+
| `onDocumentLoaded` | `(pdfViewer) => void` | - | PDF loaded callback |
|
|
103
|
+
| `onEventBusReady` | `(eventBus) => void` | - | PDF.js EventBus ready |
|
|
104
|
+
|
|
105
|
+
### 🎨 Custom UI
|
|
106
|
+
|
|
107
|
+
#### Custom Toolbar
|
|
108
|
+
|
|
109
|
+
```jsx
|
|
110
|
+
<PdfViewer
|
|
111
|
+
url={pdfUrl}
|
|
112
|
+
toolbar={(context) => (
|
|
113
|
+
<>
|
|
114
|
+
<button onClick={() => console.log(context.pdfViewer)}>
|
|
115
|
+
PDF Viewer
|
|
116
|
+
</button>
|
|
117
|
+
<button onClick={context.toggleSidebar}>
|
|
118
|
+
Toggle Sidebar
|
|
119
|
+
</button>
|
|
120
|
+
<button onClick={() => context.setSidebarCollapsed(false)}>
|
|
121
|
+
Open Sidebar
|
|
122
|
+
</button>
|
|
123
|
+
<button onClick={() => context.setSidebarCollapsed(true)}>
|
|
124
|
+
Close Sidebar
|
|
125
|
+
</button>
|
|
126
|
+
</>
|
|
127
|
+
)}
|
|
128
|
+
/>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Custom Sidebar
|
|
132
|
+
|
|
133
|
+
```jsx
|
|
134
|
+
<PdfViewer
|
|
135
|
+
url={pdfUrl}
|
|
136
|
+
sidebar={(context) => (
|
|
137
|
+
<>
|
|
138
|
+
<button onClick={() => console.log(context.pdfViewer)}>
|
|
139
|
+
PDF Viewer
|
|
140
|
+
</button>
|
|
141
|
+
<button onClick={() => {
|
|
142
|
+
context.pdfViewer?.scrollPageIntoView({
|
|
143
|
+
pageNumber: 1
|
|
144
|
+
})
|
|
145
|
+
}}>
|
|
146
|
+
page1
|
|
147
|
+
</button>
|
|
148
|
+
<button onClick={() => {
|
|
149
|
+
context.pdfViewer?.scrollPageIntoView({
|
|
150
|
+
pageNumber: 10
|
|
151
|
+
})
|
|
152
|
+
}}>
|
|
153
|
+
page 10
|
|
154
|
+
</button>
|
|
155
|
+
<button onClick={() => {
|
|
156
|
+
context.pdfViewer?.scrollPageIntoView({
|
|
157
|
+
pageNumber: 100
|
|
158
|
+
})
|
|
159
|
+
}}>
|
|
160
|
+
page 100
|
|
161
|
+
</button>
|
|
162
|
+
</>
|
|
163
|
+
)}
|
|
164
|
+
/>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Custom Actions
|
|
168
|
+
|
|
169
|
+
```jsx
|
|
170
|
+
<PdfViewer
|
|
171
|
+
url={pdfUrl}
|
|
172
|
+
actions={(context) => (
|
|
173
|
+
<>
|
|
174
|
+
<button onClick={() => console.log(context.pdfViewer)}>
|
|
175
|
+
PDF Viewer
|
|
176
|
+
</button>
|
|
177
|
+
<button onClick={context.toggleSidebar}>
|
|
178
|
+
Toggle Sidebar
|
|
179
|
+
</button>
|
|
180
|
+
<button onClick={() => context.setSidebarCollapsed(false)}>
|
|
181
|
+
Open Sidebar
|
|
182
|
+
</button>
|
|
183
|
+
<button onClick={() => context.setSidebarCollapsed(true)}>
|
|
184
|
+
Close Sidebar
|
|
185
|
+
</button>
|
|
186
|
+
</>
|
|
187
|
+
)}
|
|
188
|
+
/>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## ✍️ PdfAnnotator
|
|
194
|
+
|
|
195
|
+
An advanced PDF viewer with annotation capabilities.
|
|
196
|
+
|
|
197
|
+
### Props
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
| Prop | Type | Default | Description |
|
|
201
|
+
| ------------------------- | ------------------------------- | --------------------------------- | --------------------------- |
|
|
202
|
+
| `user` | `{ id: string; name: string }` | `{ id: 'null', name: 'unknown' }` | Annotation author |
|
|
203
|
+
| `enableNativeAnnotations` | `boolean` | `false` | Load native PDF annotations |
|
|
204
|
+
| `initialAnnotations` | `IAnnotationStore[]` | `[]` | Existing annotations |
|
|
205
|
+
| `defaultOptions` | `DeepPartial` | - | Default annotator options |
|
|
206
|
+
| `onSave` | `(annotations) => void` | - | Save callback |
|
|
207
|
+
| `onLoad` | `() => void` | - | Load complete |
|
|
208
|
+
| `onAnnotationAdded` | `(annotation) => void` | - | Add callback |
|
|
209
|
+
| `onAnnotationDeleted` | `(id) => void` | - | Delete callback |
|
|
210
|
+
| `onAnnotationUpdated` | `(annotation) => void` | - | Update callback |
|
|
211
|
+
| `onAnnotationSelected` | `(annotation, isClick) => void` | - | Select callback |
|
|
212
|
+
| `actions` | `ReactNode | Component` | - | Custom action buttons |
|
|
213
|
+
|
|
214
|
+
### ⚙️ defaultOptions (Enterprise Design)
|
|
215
|
+
|
|
216
|
+
#### ✅ DeepPartial + Deep Merge
|
|
217
|
+
|
|
218
|
+
`defaultOptions` is not a full config override.
|
|
219
|
+
|
|
220
|
+
- It is defined as `DeepPartial<PdfAnnotatorOptions> `
|
|
221
|
+
- It will be deep merged with the system default configuration
|
|
222
|
+
|
|
223
|
+
This ensures:
|
|
224
|
+
|
|
225
|
+
- You only override what you need
|
|
226
|
+
- System defaults remain stable
|
|
227
|
+
- Safe for long-term enterprise use
|
|
228
|
+
|
|
229
|
+
#### Example
|
|
230
|
+
```tsx
|
|
231
|
+
import qiantubifengshouxietiFont from './fonts/qiantubifengshouxieti.ttf';
|
|
232
|
+
|
|
233
|
+
<PdfAnnotator
|
|
234
|
+
url="sample.pdf"
|
|
235
|
+
defaultOptions={{
|
|
236
|
+
colors: ['#000', '#1677ff'],
|
|
237
|
+
signature: {
|
|
238
|
+
colors: ['#000000', '#ff0000', '#1677ff'],
|
|
239
|
+
type: 'Upload',
|
|
240
|
+
maxSize: 1024 * 1024 * 5,
|
|
241
|
+
accept: '.png,.jpg,.jpeg,.bmp',
|
|
242
|
+
defaultSignature: ['data:image/png;base64,...'],
|
|
243
|
+
defaultFont: [
|
|
244
|
+
{
|
|
245
|
+
label: '楷体',
|
|
246
|
+
value: 'STKaiti',
|
|
247
|
+
external: false
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
label: '千图笔锋手写体',
|
|
251
|
+
value: 'qiantubifengshouxieti',
|
|
252
|
+
external: true,
|
|
253
|
+
url: qiantubifengshouxietiFont
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
label: '平方长安体',
|
|
257
|
+
value: 'PingFangChangAnTi-2',
|
|
258
|
+
external: true,
|
|
259
|
+
url: 'http://server/PingFangChangAnTi-2.ttf'
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
stamp: {
|
|
264
|
+
maxSize: 1024 * 1024 * 5,
|
|
265
|
+
accept: '.png,.jpg,.jpeg,.bmp',
|
|
266
|
+
defaultStamp: ['data:image/png;base64,...'],
|
|
267
|
+
editor: {
|
|
268
|
+
defaultBackgroundColor: '#2f9e44',
|
|
269
|
+
defaultBorderColor: '#2b8a3e',
|
|
270
|
+
defaultBorderStyle: 'none',
|
|
271
|
+
defaultTextColor: '#fff',
|
|
272
|
+
defaultFont: [
|
|
273
|
+
{
|
|
274
|
+
label: '楷体',
|
|
275
|
+
value: 'STKaiti'
|
|
276
|
+
}
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}}
|
|
281
|
+
/>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### 🎨 Custom UI
|
|
285
|
+
|
|
286
|
+
#### Custom Actions
|
|
287
|
+
|
|
288
|
+
```jsx
|
|
289
|
+
<PdfAnnotator
|
|
290
|
+
url={pdfUrl}
|
|
291
|
+
actions={({ save, exportToPdf, exportToExcel }) => (
|
|
292
|
+
<>
|
|
293
|
+
<button onClick={save}>Save</button>
|
|
294
|
+
<button onClick={() => exportToPdf('annotations')}>
|
|
295
|
+
Export PDF
|
|
296
|
+
</button>
|
|
297
|
+
<button onClick={() => exportToExcel('annotations')}>
|
|
298
|
+
Export Excel
|
|
299
|
+
</button>
|
|
300
|
+
</>
|
|
301
|
+
)}
|
|
302
|
+
/>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 🖋 Signature & Stamp Configuration
|
|
306
|
+
|
|
307
|
+
```jsx
|
|
308
|
+
<PdfAnnotator
|
|
309
|
+
url={pdfUrl}
|
|
310
|
+
defaultOptions={{
|
|
311
|
+
signature: {
|
|
312
|
+
defaultSignature: ['data:image/png;base64,...'],
|
|
313
|
+
defaultFont: [
|
|
314
|
+
{
|
|
315
|
+
label: 'Custom Font',
|
|
316
|
+
value: 'MyFont',
|
|
317
|
+
external: true,
|
|
318
|
+
url: '/fonts/myfont.ttf'
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
},
|
|
322
|
+
stamp: {
|
|
323
|
+
defaultStamp: ['data:image/png;base64,...']
|
|
324
|
+
}
|
|
325
|
+
}}
|
|
326
|
+
/>
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
# 🌍 Browser Support
|
|
330
|
+
|
|
331
|
+
- Chrome (latest)
|
|
332
|
+
- Firefox (latest)
|
|
333
|
+
- Safari (latest)
|
|
334
|
+
- Edge (latest)
|
|
335
|
+
|
|
336
|
+
# 📄 License
|
|
337
|
+
|
|
338
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e={};exports.default=e;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var z={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0},Z=/([astvzqmhlc])([^astvzqmhlc]*)/gi,_=/-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/gi;function g(o){const n=o.match(_);return n?n.map(Number):[]}function V(o){const n=[],t=String(o).trim();return t[0]!=="M"&&t[0]!=="m"||t.replace(Z,(l,r,a)=>{const s=g(a);let i=r.toLowerCase(),c=r;if(i==="m"&&s.length>2&&(n.push([c,...s.splice(0,2)]),i="l",c=c==="m"?"l":"L"),s.length<z[i])return"";for(n.push([c,...s.splice(0,z[i])]);s.length>=z[i]&&s.length&&z[i];)n.push([c,...s.splice(0,z[i])]);return""}),n}function B(o,n){const t=o.x*Math.cos(n)-o.y*Math.sin(n),l=o.y*Math.cos(n)+o.x*Math.sin(n);o.x=t,o.y=l}function j(o,n,t){o.x+=n,o.y+=t}function H(o,n){o.x*=n,o.y*=n}var C=class L{constructor(n){this.commands=[],n&&n instanceof L?this.commands.push(...n.commands):n&&(this.commands=V(n))}addPath(n){n&&n instanceof L&&this.commands.push(...n.commands)}moveTo(n,t){this.commands.push(["M",n,t])}lineTo(n,t){this.commands.push(["L",n,t])}arc(n,t,l,r,a,s){this.commands.push(["AC",n,t,l,r,a,!!s])}arcTo(n,t,l,r,a){this.commands.push(["AT",n,t,l,r,a])}ellipse(n,t,l,r,a,s,i,c){this.commands.push(["E",n,t,l,r,a,s,i,!!c])}closePath(){this.commands.push(["Z"])}bezierCurveTo(n,t,l,r,a,s){this.commands.push(["C",n,t,l,r,a,s])}quadraticCurveTo(n,t,l,r){this.commands.push(["Q",n,t,l,r])}rect(n,t,l,r){this.commands.push(["R",n,t,l,r])}roundRect(n,t,l,r,a){typeof a>"u"?this.commands.push(["RR",n,t,l,r,0]):this.commands.push(["RR",n,t,l,r,a])}};function A(o,n){let t=0,l=0,r,a,s,i,c,u,m,q,F,d,$,G,E,p,f,w,I,b,k,S,Q,P=null,R=null,y=null,T=null,v=null,M=null;o.beginPath();for(let h=0;h<n.length;++h){b=n[h][0],b!=="S"&&b!=="s"&&b!=="C"&&b!=="c"&&(P=null,R=null),b!=="T"&&b!=="t"&&b!=="Q"&&b!=="q"&&(y=null,T=null);let e;switch(b){case"m":case"M":e=n[h],b==="m"?(t+=e[1],l+=e[2]):(t=e[1],l=e[2]),(b==="M"||!v)&&(v={x:t,y:l}),o.moveTo(t,l);break;case"l":e=n[h],t+=e[1],l+=e[2],o.lineTo(t,l);break;case"L":e=n[h],t=e[1],l=e[2],o.lineTo(t,l);break;case"H":e=n[h],t=e[1],o.lineTo(t,l);break;case"h":e=n[h],t+=e[1],o.lineTo(t,l);break;case"V":e=n[h],l=e[1],o.lineTo(t,l);break;case"v":e=n[h],l+=e[1],o.lineTo(t,l);break;case"a":case"A":if(e=n[h],M===null)throw new Error("This should never happen");b==="a"?(t+=e[6],l+=e[7]):(t=e[6],l=e[7]),p=e[1],f=e[2],m=e[3]*Math.PI/180,s=!!e[4],i=!!e[5],c={x:t,y:l},u={x:(M.x-c.x)/2,y:(M.y-c.y)/2},B(u,-m),q=u.x*u.x/(p*p)+u.y*u.y/(f*f),q>1&&(q=Math.sqrt(q),p*=q,f*=q),k={x:p*u.y/f,y:-(f*u.x)/p},F=p*p*f*f,d=p*p*u.y*u.y+f*f*u.x*u.x,i!==s?H(k,Math.sqrt((F-d)/d)||0):H(k,-Math.sqrt((F-d)/d)||0),a=Math.atan2((u.y-k.y)/f,(u.x-k.x)/p),r=Math.atan2(-(u.y+k.y)/f,-(u.x+k.x)/p),B(k,m),j(k,(c.x+M.x)/2,(c.y+M.y)/2),o.save(),o.translate(k.x,k.y),o.rotate(m),o.scale(p,f),o.arc(0,0,1,a,r,!i),o.restore();break;case"C":e=n[h],P=e[3],R=e[4],t=e[5],l=e[6],o.bezierCurveTo(e[1],e[2],P,R,t,l);break;case"c":e=n[h],o.bezierCurveTo(e[1]+t,e[2]+l,e[3]+t,e[4]+l,e[5]+t,e[6]+l),P=e[3]+t,R=e[4]+l,t+=e[5],l+=e[6];break;case"S":e=n[h],(P===null||R===null)&&(P=t,R=l),o.bezierCurveTo(2*t-P,2*l-R,e[1],e[2],e[3],e[4]),P=e[1],R=e[2],t=e[3],l=e[4];break;case"s":e=n[h],(P===null||R===null)&&(P=t,R=l),o.bezierCurveTo(2*t-P,2*l-R,e[1]+t,e[2]+l,e[3]+t,e[4]+l),P=e[1]+t,R=e[2]+l,t+=e[3],l+=e[4];break;case"Q":e=n[h],y=e[1],T=e[2],t=e[3],l=e[4],o.quadraticCurveTo(y,T,t,l);break;case"q":e=n[h],y=e[1]+t,T=e[2]+l,t+=e[3],l+=e[4],o.quadraticCurveTo(y,T,t,l);break;case"T":e=n[h],(y===null||T===null)&&(y=t,T=l),y=2*t-y,T=2*l-T,t=e[1],l=e[2],o.quadraticCurveTo(y,T,t,l);break;case"t":e=n[h],(y===null||T===null)&&(y=t,T=l),y=2*t-y,T=2*l-T,t+=e[1],l+=e[2],o.quadraticCurveTo(y,T,t,l);break;case"z":case"Z":v&&(t=v.x,l=v.y),v=null,o.closePath();break;case"AC":e=n[h],t=e[1],l=e[2],E=e[3],a=e[4],r=e[5],S=e[6],o.arc(t,l,E,a,r,S);break;case"AT":e=n[h],$=e[1],G=e[2],t=e[3],l=e[4],E=e[5],o.arcTo($,G,t,l,E);break;case"E":e=n[h],t=e[1],l=e[2],p=e[3],f=e[4],m=e[5],a=e[6],r=e[7],S=e[8],o.save(),o.translate(t,l),o.rotate(m),o.scale(p,f),o.arc(0,0,1,a,r,S),o.restore();break;case"R":e=n[h],t=e[1],l=e[2],w=e[3],I=e[4],v={x:t,y:l},o.rect(t,l,w,I);break;case"RR":e=n[h],t=e[1],l=e[2],w=e[3],I=e[4],Q=e[5],v={x:t,y:l},o.roundRect(t,l,w,I,Q);break;default:throw new Error(`Invalid path command: ${b}`)}M?(M.x=t,M.y=l):M={x:t,y:l}}}function N(o,n,t,l,r=0){if(typeof r=="number"&&(r=[r]),Array.isArray(r)){if(r.length===0||r.length>4)throw new RangeError(`Failed to execute 'roundRect' on '${this.constructor.name}': ${r.length} radii provided. Between one and four radii are necessary.`);r.forEach(m=>{if(m<0)throw new RangeError(`Failed to execute 'roundRect' on '${this.constructor.name}': Radius value ${m} is negative.`)})}else return;if(r.length===1&&r[0]===0){this.rect(o,n,t,l);return}const a=Math.min(t,l)/2,s=Math.min(a,r[0]);let i=s,c=s,u=s;r.length===2&&(i=Math.min(a,r[1]),u=i),r.length===3&&(i=Math.min(a,r[1]),u=i,c=Math.min(a,r[2])),r.length===4&&(i=Math.min(a,r[1]),c=Math.min(a,r[2]),u=Math.min(a,r[3])),this.moveTo(o,n+l-u),this.arcTo(o,n,o+s,n,s),this.arcTo(o+t,n,o+t,n+i,i),this.arcTo(o+t,n+l,o+t-c,n+l,c),this.arcTo(o,n+l,o,n+l-u,u),this.closePath()}function O(o){if(!o)return;const n=o.prototype.clip,t=o.prototype.fill,l=o.prototype.stroke,r=o.prototype.isPointInPath;o.prototype.clip=function(...s){if(s[0]instanceof C){const c=s[0],u=s[1]||"nonzero";return A(this,c.commands),n.apply(this,[u])}const i=s[0]||"nonzero";return n.apply(this,[i])},o.prototype.fill=function(...s){if(s[0]instanceof C){const c=s[0],u=s[1]||"nonzero";return A(this,c.commands),t.apply(this,[u])}const i=s[0]||"nonzero";return t.apply(this,[i])},o.prototype.stroke=function(s){s&&A(this,s.commands),l.apply(this)},o.prototype.isPointInPath=function(...s){if(s[0]instanceof C){const i=s[0],c=s[1],u=s[2],m=s[3]||"nonzero";return A(this,i.commands),r.apply(this,[c,u,m])}return r.apply(this,s)}}function U(o){o&&!o.prototype.roundRect&&(o.prototype.roundRect=N)}function J(o){o&&!o.prototype.roundRect&&(o.prototype.roundRect=N)}exports.Path2D=C;exports.applyPath2DToCanvasRenderingContext=O;exports.applyRoundRectToCanvasRenderingContext2D=U;exports.applyRoundRectToPath2D=J;exports.buildPath=A;exports.parsePath=V;exports.roundRect=N;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
var A = {
|
|
2
|
+
a: 7,
|
|
3
|
+
c: 6,
|
|
4
|
+
h: 1,
|
|
5
|
+
l: 2,
|
|
6
|
+
m: 2,
|
|
7
|
+
q: 4,
|
|
8
|
+
s: 4,
|
|
9
|
+
t: 2,
|
|
10
|
+
v: 1,
|
|
11
|
+
z: 0
|
|
12
|
+
}, V = /([astvzqmhlc])([^astvzqmhlc]*)/gi, Z = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/gi;
|
|
13
|
+
function _(o) {
|
|
14
|
+
const n = o.match(Z);
|
|
15
|
+
return n ? n.map(Number) : [];
|
|
16
|
+
}
|
|
17
|
+
function U(o) {
|
|
18
|
+
const n = [], t = String(o).trim();
|
|
19
|
+
return t[0] !== "M" && t[0] !== "m" || t.replace(V, (l, r, a) => {
|
|
20
|
+
const s = _(a);
|
|
21
|
+
let c = r.toLowerCase(), i = r;
|
|
22
|
+
if (c === "m" && s.length > 2 && (n.push([i, ...s.splice(0, 2)]), c = "l", i = i === "m" ? "l" : "L"), s.length < A[c])
|
|
23
|
+
return "";
|
|
24
|
+
for (n.push([i, ...s.splice(0, A[c])]); s.length >= A[c] && s.length && A[c]; )
|
|
25
|
+
n.push([i, ...s.splice(0, A[c])]);
|
|
26
|
+
return "";
|
|
27
|
+
}), n;
|
|
28
|
+
}
|
|
29
|
+
function B(o, n) {
|
|
30
|
+
const t = o.x * Math.cos(n) - o.y * Math.sin(n), l = o.y * Math.cos(n) + o.x * Math.sin(n);
|
|
31
|
+
o.x = t, o.y = l;
|
|
32
|
+
}
|
|
33
|
+
function j(o, n, t) {
|
|
34
|
+
o.x += n, o.y += t;
|
|
35
|
+
}
|
|
36
|
+
function C(o, n) {
|
|
37
|
+
o.x *= n, o.y *= n;
|
|
38
|
+
}
|
|
39
|
+
var N = class S {
|
|
40
|
+
constructor(n) {
|
|
41
|
+
this.commands = [], n && n instanceof S ? this.commands.push(...n.commands) : n && (this.commands = U(n));
|
|
42
|
+
}
|
|
43
|
+
addPath(n) {
|
|
44
|
+
n && n instanceof S && this.commands.push(...n.commands);
|
|
45
|
+
}
|
|
46
|
+
moveTo(n, t) {
|
|
47
|
+
this.commands.push(["M", n, t]);
|
|
48
|
+
}
|
|
49
|
+
lineTo(n, t) {
|
|
50
|
+
this.commands.push(["L", n, t]);
|
|
51
|
+
}
|
|
52
|
+
arc(n, t, l, r, a, s) {
|
|
53
|
+
this.commands.push(["AC", n, t, l, r, a, !!s]);
|
|
54
|
+
}
|
|
55
|
+
arcTo(n, t, l, r, a) {
|
|
56
|
+
this.commands.push(["AT", n, t, l, r, a]);
|
|
57
|
+
}
|
|
58
|
+
ellipse(n, t, l, r, a, s, c, i) {
|
|
59
|
+
this.commands.push(["E", n, t, l, r, a, s, c, !!i]);
|
|
60
|
+
}
|
|
61
|
+
closePath() {
|
|
62
|
+
this.commands.push(["Z"]);
|
|
63
|
+
}
|
|
64
|
+
bezierCurveTo(n, t, l, r, a, s) {
|
|
65
|
+
this.commands.push(["C", n, t, l, r, a, s]);
|
|
66
|
+
}
|
|
67
|
+
quadraticCurveTo(n, t, l, r) {
|
|
68
|
+
this.commands.push(["Q", n, t, l, r]);
|
|
69
|
+
}
|
|
70
|
+
rect(n, t, l, r) {
|
|
71
|
+
this.commands.push(["R", n, t, l, r]);
|
|
72
|
+
}
|
|
73
|
+
roundRect(n, t, l, r, a) {
|
|
74
|
+
typeof a > "u" ? this.commands.push(["RR", n, t, l, r, 0]) : this.commands.push(["RR", n, t, l, r, a]);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
function F(o, n) {
|
|
78
|
+
let t = 0, l = 0, r, a, s, c, i, u, k, q, L, z, $, G, E, p, f, w, I, b, R, d, Q, m = null, P = null, y = null, T = null, v = null, M = null;
|
|
79
|
+
o.beginPath();
|
|
80
|
+
for (let h = 0; h < n.length; ++h) {
|
|
81
|
+
b = n[h][0], b !== "S" && b !== "s" && b !== "C" && b !== "c" && (m = null, P = null), b !== "T" && b !== "t" && b !== "Q" && b !== "q" && (y = null, T = null);
|
|
82
|
+
let e;
|
|
83
|
+
switch (b) {
|
|
84
|
+
case "m":
|
|
85
|
+
case "M":
|
|
86
|
+
e = n[h], b === "m" ? (t += e[1], l += e[2]) : (t = e[1], l = e[2]), (b === "M" || !v) && (v = { x: t, y: l }), o.moveTo(t, l);
|
|
87
|
+
break;
|
|
88
|
+
case "l":
|
|
89
|
+
e = n[h], t += e[1], l += e[2], o.lineTo(t, l);
|
|
90
|
+
break;
|
|
91
|
+
case "L":
|
|
92
|
+
e = n[h], t = e[1], l = e[2], o.lineTo(t, l);
|
|
93
|
+
break;
|
|
94
|
+
case "H":
|
|
95
|
+
e = n[h], t = e[1], o.lineTo(t, l);
|
|
96
|
+
break;
|
|
97
|
+
case "h":
|
|
98
|
+
e = n[h], t += e[1], o.lineTo(t, l);
|
|
99
|
+
break;
|
|
100
|
+
case "V":
|
|
101
|
+
e = n[h], l = e[1], o.lineTo(t, l);
|
|
102
|
+
break;
|
|
103
|
+
case "v":
|
|
104
|
+
e = n[h], l += e[1], o.lineTo(t, l);
|
|
105
|
+
break;
|
|
106
|
+
case "a":
|
|
107
|
+
case "A":
|
|
108
|
+
if (e = n[h], M === null)
|
|
109
|
+
throw new Error("This should never happen");
|
|
110
|
+
b === "a" ? (t += e[6], l += e[7]) : (t = e[6], l = e[7]), p = e[1], f = e[2], k = e[3] * Math.PI / 180, s = !!e[4], c = !!e[5], i = { x: t, y: l }, u = {
|
|
111
|
+
x: (M.x - i.x) / 2,
|
|
112
|
+
y: (M.y - i.y) / 2
|
|
113
|
+
}, B(u, -k), q = u.x * u.x / (p * p) + u.y * u.y / (f * f), q > 1 && (q = Math.sqrt(q), p *= q, f *= q), R = {
|
|
114
|
+
x: p * u.y / f,
|
|
115
|
+
y: -(f * u.x) / p
|
|
116
|
+
}, L = p * p * f * f, z = p * p * u.y * u.y + f * f * u.x * u.x, c !== s ? C(R, Math.sqrt((L - z) / z) || 0) : C(R, -Math.sqrt((L - z) / z) || 0), a = Math.atan2((u.y - R.y) / f, (u.x - R.x) / p), r = Math.atan2(-(u.y + R.y) / f, -(u.x + R.x) / p), B(R, k), j(R, (i.x + M.x) / 2, (i.y + M.y) / 2), o.save(), o.translate(R.x, R.y), o.rotate(k), o.scale(p, f), o.arc(0, 0, 1, a, r, !c), o.restore();
|
|
117
|
+
break;
|
|
118
|
+
case "C":
|
|
119
|
+
e = n[h], m = e[3], P = e[4], t = e[5], l = e[6], o.bezierCurveTo(e[1], e[2], m, P, t, l);
|
|
120
|
+
break;
|
|
121
|
+
case "c":
|
|
122
|
+
e = n[h], o.bezierCurveTo(e[1] + t, e[2] + l, e[3] + t, e[4] + l, e[5] + t, e[6] + l), m = e[3] + t, P = e[4] + l, t += e[5], l += e[6];
|
|
123
|
+
break;
|
|
124
|
+
case "S":
|
|
125
|
+
e = n[h], (m === null || P === null) && (m = t, P = l), o.bezierCurveTo(2 * t - m, 2 * l - P, e[1], e[2], e[3], e[4]), m = e[1], P = e[2], t = e[3], l = e[4];
|
|
126
|
+
break;
|
|
127
|
+
case "s":
|
|
128
|
+
e = n[h], (m === null || P === null) && (m = t, P = l), o.bezierCurveTo(2 * t - m, 2 * l - P, e[1] + t, e[2] + l, e[3] + t, e[4] + l), m = e[1] + t, P = e[2] + l, t += e[3], l += e[4];
|
|
129
|
+
break;
|
|
130
|
+
case "Q":
|
|
131
|
+
e = n[h], y = e[1], T = e[2], t = e[3], l = e[4], o.quadraticCurveTo(y, T, t, l);
|
|
132
|
+
break;
|
|
133
|
+
case "q":
|
|
134
|
+
e = n[h], y = e[1] + t, T = e[2] + l, t += e[3], l += e[4], o.quadraticCurveTo(y, T, t, l);
|
|
135
|
+
break;
|
|
136
|
+
case "T":
|
|
137
|
+
e = n[h], (y === null || T === null) && (y = t, T = l), y = 2 * t - y, T = 2 * l - T, t = e[1], l = e[2], o.quadraticCurveTo(y, T, t, l);
|
|
138
|
+
break;
|
|
139
|
+
case "t":
|
|
140
|
+
e = n[h], (y === null || T === null) && (y = t, T = l), y = 2 * t - y, T = 2 * l - T, t += e[1], l += e[2], o.quadraticCurveTo(y, T, t, l);
|
|
141
|
+
break;
|
|
142
|
+
case "z":
|
|
143
|
+
case "Z":
|
|
144
|
+
v && (t = v.x, l = v.y), v = null, o.closePath();
|
|
145
|
+
break;
|
|
146
|
+
case "AC":
|
|
147
|
+
e = n[h], t = e[1], l = e[2], E = e[3], a = e[4], r = e[5], d = e[6], o.arc(t, l, E, a, r, d);
|
|
148
|
+
break;
|
|
149
|
+
case "AT":
|
|
150
|
+
e = n[h], $ = e[1], G = e[2], t = e[3], l = e[4], E = e[5], o.arcTo($, G, t, l, E);
|
|
151
|
+
break;
|
|
152
|
+
case "E":
|
|
153
|
+
e = n[h], t = e[1], l = e[2], p = e[3], f = e[4], k = e[5], a = e[6], r = e[7], d = e[8], o.save(), o.translate(t, l), o.rotate(k), o.scale(p, f), o.arc(0, 0, 1, a, r, d), o.restore();
|
|
154
|
+
break;
|
|
155
|
+
case "R":
|
|
156
|
+
e = n[h], t = e[1], l = e[2], w = e[3], I = e[4], v = { x: t, y: l }, o.rect(t, l, w, I);
|
|
157
|
+
break;
|
|
158
|
+
case "RR":
|
|
159
|
+
e = n[h], t = e[1], l = e[2], w = e[3], I = e[4], Q = e[5], v = { x: t, y: l }, o.roundRect(t, l, w, I, Q);
|
|
160
|
+
break;
|
|
161
|
+
default:
|
|
162
|
+
throw new Error(`Invalid path command: ${b}`);
|
|
163
|
+
}
|
|
164
|
+
M ? (M.x = t, M.y = l) : M = { x: t, y: l };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function H(o, n, t, l, r = 0) {
|
|
168
|
+
if (typeof r == "number" && (r = [r]), Array.isArray(r)) {
|
|
169
|
+
if (r.length === 0 || r.length > 4)
|
|
170
|
+
throw new RangeError(
|
|
171
|
+
`Failed to execute 'roundRect' on '${this.constructor.name}': ${r.length} radii provided. Between one and four radii are necessary.`
|
|
172
|
+
);
|
|
173
|
+
r.forEach((k) => {
|
|
174
|
+
if (k < 0)
|
|
175
|
+
throw new RangeError(
|
|
176
|
+
`Failed to execute 'roundRect' on '${this.constructor.name}': Radius value ${k} is negative.`
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
} else
|
|
180
|
+
return;
|
|
181
|
+
if (r.length === 1 && r[0] === 0) {
|
|
182
|
+
this.rect(o, n, t, l);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const a = Math.min(t, l) / 2, s = Math.min(a, r[0]);
|
|
186
|
+
let c = s, i = s, u = s;
|
|
187
|
+
r.length === 2 && (c = Math.min(a, r[1]), u = c), r.length === 3 && (c = Math.min(a, r[1]), u = c, i = Math.min(a, r[2])), r.length === 4 && (c = Math.min(a, r[1]), i = Math.min(a, r[2]), u = Math.min(a, r[3])), this.moveTo(o, n + l - u), this.arcTo(o, n, o + s, n, s), this.arcTo(o + t, n, o + t, n + c, c), this.arcTo(o + t, n + l, o + t - i, n + l, i), this.arcTo(o, n + l, o, n + l - u, u), this.closePath();
|
|
188
|
+
}
|
|
189
|
+
function J(o) {
|
|
190
|
+
if (!o) return;
|
|
191
|
+
const n = o.prototype.clip, t = o.prototype.fill, l = o.prototype.stroke, r = o.prototype.isPointInPath;
|
|
192
|
+
o.prototype.clip = function(...s) {
|
|
193
|
+
if (s[0] instanceof N) {
|
|
194
|
+
const i = s[0], u = s[1] || "nonzero";
|
|
195
|
+
return F(this, i.commands), n.apply(this, [u]);
|
|
196
|
+
}
|
|
197
|
+
const c = s[0] || "nonzero";
|
|
198
|
+
return n.apply(this, [c]);
|
|
199
|
+
}, o.prototype.fill = function(...s) {
|
|
200
|
+
if (s[0] instanceof N) {
|
|
201
|
+
const i = s[0], u = s[1] || "nonzero";
|
|
202
|
+
return F(this, i.commands), t.apply(this, [u]);
|
|
203
|
+
}
|
|
204
|
+
const c = s[0] || "nonzero";
|
|
205
|
+
return t.apply(this, [c]);
|
|
206
|
+
}, o.prototype.stroke = function(s) {
|
|
207
|
+
s && F(this, s.commands), l.apply(this);
|
|
208
|
+
}, o.prototype.isPointInPath = function(...s) {
|
|
209
|
+
if (s[0] instanceof N) {
|
|
210
|
+
const c = s[0], i = s[1], u = s[2], k = s[3] || "nonzero";
|
|
211
|
+
return F(this, c.commands), r.apply(this, [i, u, k]);
|
|
212
|
+
}
|
|
213
|
+
return r.apply(this, s);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function K(o) {
|
|
217
|
+
o && !o.prototype.roundRect && (o.prototype.roundRect = H);
|
|
218
|
+
}
|
|
219
|
+
function O(o) {
|
|
220
|
+
o && !o.prototype.roundRect && (o.prototype.roundRect = H);
|
|
221
|
+
}
|
|
222
|
+
export {
|
|
223
|
+
N as Path2D,
|
|
224
|
+
J as applyPath2DToCanvasRenderingContext,
|
|
225
|
+
K as applyRoundRectToCanvasRenderingContext2D,
|
|
226
|
+
O as applyRoundRectToPath2D,
|
|
227
|
+
F as buildPath,
|
|
228
|
+
U as parsePath,
|
|
229
|
+
H as roundRect
|
|
230
|
+
};
|