@operato/scene-pdf 9.0.0-beta.12
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/README.md +41 -0
- package/assets/favicon.ico +0 -0
- package/assets/images/spinner.png +0 -0
- package/dist/editors/index.d.ts +2 -0
- package/dist/editors/index.js +2 -0
- package/dist/editors/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/pdf-page.d.ts +99 -0
- package/dist/pdf-page.js +249 -0
- package/dist/pdf-page.js.map +1 -0
- package/dist/templates/index.d.ts +17 -0
- package/dist/templates/index.js +3 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/pdf-page.d.ts +17 -0
- package/dist/templates/pdf-page.js +18 -0
- package/dist/templates/pdf-page.js.map +1 -0
- package/helps/scene/component/pdf-page.ja.md +26 -0
- package/helps/scene/component/pdf-page.ko.md +26 -0
- package/helps/scene/component/pdf-page.md +26 -0
- package/helps/scene/component/pdf-page.ms.md +26 -0
- package/helps/scene/component/pdf-page.zh.md +26 -0
- package/icons/icon-pdf-page.png +0 -0
- package/package.json +64 -0
- package/things-scene.config.js +7 -0
- package/translations/en.json +6 -0
- package/translations/ja.json +6 -0
- package/translations/ko.json +6 -0
- package/translations/ms.json +6 -0
- package/translations/zh.json +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# \<scene-pdf>
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm i scene-pdf
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Linting and formatting
|
|
16
|
+
|
|
17
|
+
To scan the project for linting and formatting errors, run
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm run lint
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
To automatically fix linting and formatting errors, run
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm run format
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Tooling configs
|
|
30
|
+
|
|
31
|
+
For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project.
|
|
32
|
+
|
|
33
|
+
If you customize the configuration a lot, you can consider moving them to individual files.
|
|
34
|
+
|
|
35
|
+
## Local Demo with `web-dev-server`
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm start
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
To run a local development server that serves the basic demo located in `demo/index.html`
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/editors/index.ts"],"names":[],"mappings":"AAAA,eAAe,EAAE,CAAC","sourcesContent":["export default [];\n"]}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,eAAe,CAAA;AACnC,eAAe,CAAC,OAAO,CAAC,CAAA","sourcesContent":["import PDFPage from './pdf-page.js'\nexport default [PDFPage]\n"]}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Properties, Shape } from '@hatiolab/things-scene';
|
|
2
|
+
declare const PDFPage_base: typeof Shape;
|
|
3
|
+
export default class PDFPage extends PDFPage_base {
|
|
4
|
+
private scaleIndex;
|
|
5
|
+
private displayScale;
|
|
6
|
+
private offsetX;
|
|
7
|
+
private offsetY;
|
|
8
|
+
private pdfDoc;
|
|
9
|
+
private canvas;
|
|
10
|
+
private renderTask;
|
|
11
|
+
private page;
|
|
12
|
+
private documentSize;
|
|
13
|
+
private position;
|
|
14
|
+
ready(): Promise<void>;
|
|
15
|
+
dispose(): void;
|
|
16
|
+
loadPDF(): Promise<void>;
|
|
17
|
+
onchange(after: Properties, before: Properties): void;
|
|
18
|
+
/**
|
|
19
|
+
* Adjusts the PDF display scale and offsets based on the fit mode.
|
|
20
|
+
*
|
|
21
|
+
* @async
|
|
22
|
+
* @method fit
|
|
23
|
+
* @memberof PdfPage
|
|
24
|
+
* @returns {Promise<void>}
|
|
25
|
+
*
|
|
26
|
+
* @description
|
|
27
|
+
* This method adjusts the display scale of the PDF page based on the `fit` mode specified in the component's state.
|
|
28
|
+
* It supports the following fit modes:
|
|
29
|
+
* - 'width': Scales the PDF to fit the width of the container.
|
|
30
|
+
* - 'height': Scales the PDF to fit the height of the container.
|
|
31
|
+
* - 'ratio': Scales the PDF to fit both the width and height of the container while maintaining the aspect ratio.
|
|
32
|
+
* - 'none': Displays the PDF at its original size.
|
|
33
|
+
*
|
|
34
|
+
* The method also calculates the appropriate offsets to center the PDF within the container when the fit mode is 'ratio'.
|
|
35
|
+
* Finally, it triggers the rendering of the PDF.
|
|
36
|
+
*/
|
|
37
|
+
fit(): Promise<void>;
|
|
38
|
+
renderPDF(): Promise<void>;
|
|
39
|
+
render(ctx: CanvasRenderingContext2D): void;
|
|
40
|
+
onwheel(e: WheelEvent): void;
|
|
41
|
+
ondragstart(e: MouseEvent): void;
|
|
42
|
+
ondragmove(e: MouseEvent): void;
|
|
43
|
+
ondblclick(e: MouseEvent): void;
|
|
44
|
+
get nature(): {
|
|
45
|
+
mutable: boolean;
|
|
46
|
+
resizable: boolean;
|
|
47
|
+
rotatable: boolean;
|
|
48
|
+
properties: ({
|
|
49
|
+
type: string;
|
|
50
|
+
label: string;
|
|
51
|
+
name: string;
|
|
52
|
+
property: {
|
|
53
|
+
min: number;
|
|
54
|
+
displayField?: undefined;
|
|
55
|
+
displayFullUrl?: undefined;
|
|
56
|
+
storageFilters?: undefined;
|
|
57
|
+
useUpload?: undefined;
|
|
58
|
+
options?: undefined;
|
|
59
|
+
};
|
|
60
|
+
} | {
|
|
61
|
+
type: string;
|
|
62
|
+
label: string;
|
|
63
|
+
name: string;
|
|
64
|
+
property: {
|
|
65
|
+
displayField: string;
|
|
66
|
+
displayFullUrl: boolean;
|
|
67
|
+
storageFilters: {
|
|
68
|
+
type: ArrayConstructor;
|
|
69
|
+
value: {
|
|
70
|
+
name: string;
|
|
71
|
+
value: string;
|
|
72
|
+
}[];
|
|
73
|
+
};
|
|
74
|
+
useUpload: boolean;
|
|
75
|
+
min?: undefined;
|
|
76
|
+
options?: undefined;
|
|
77
|
+
};
|
|
78
|
+
} | {
|
|
79
|
+
type: string;
|
|
80
|
+
label: string;
|
|
81
|
+
name: string;
|
|
82
|
+
property?: undefined;
|
|
83
|
+
} | {
|
|
84
|
+
type: string;
|
|
85
|
+
label: string;
|
|
86
|
+
name: string;
|
|
87
|
+
property: {
|
|
88
|
+
options: string[];
|
|
89
|
+
min?: undefined;
|
|
90
|
+
displayField?: undefined;
|
|
91
|
+
displayFullUrl?: undefined;
|
|
92
|
+
storageFilters?: undefined;
|
|
93
|
+
useUpload?: undefined;
|
|
94
|
+
};
|
|
95
|
+
})[];
|
|
96
|
+
help: string;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export {};
|
package/dist/pdf-page.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { getDocument, GlobalWorkerOptions } from 'pdfjs-dist';
|
|
2
|
+
import { Component, RectPath, Shape } from '@hatiolab/things-scene';
|
|
3
|
+
GlobalWorkerOptions.workerSrc = '/node_modules/pdfjs-dist/build/pdf.worker.min.mjs';
|
|
4
|
+
const NATURE = {
|
|
5
|
+
mutable: false,
|
|
6
|
+
resizable: true,
|
|
7
|
+
rotatable: true,
|
|
8
|
+
properties: [
|
|
9
|
+
{
|
|
10
|
+
type: 'number',
|
|
11
|
+
label: 'round',
|
|
12
|
+
name: 'round',
|
|
13
|
+
property: { min: 0 }
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
type: 'attachment-selector',
|
|
17
|
+
label: 'pdf-file',
|
|
18
|
+
name: 'file',
|
|
19
|
+
property: {
|
|
20
|
+
displayField: 'fullpath',
|
|
21
|
+
displayFullUrl: true,
|
|
22
|
+
storageFilters: { type: Array, value: [{ name: 'category', value: 'application' }] },
|
|
23
|
+
useUpload: true
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: 'number',
|
|
28
|
+
label: 'pdf-page',
|
|
29
|
+
name: 'page'
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
type: 'select',
|
|
33
|
+
label: 'pdf-fit',
|
|
34
|
+
name: 'fit',
|
|
35
|
+
property: {
|
|
36
|
+
options: ['none', 'ratio', 'width', 'height']
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
help: 'scene/component/pdf-viewer'
|
|
41
|
+
};
|
|
42
|
+
const SCALE_LEVELS = [2, 4, 8, 16, 32];
|
|
43
|
+
const MAX_CANVAS_SIZE = 16000;
|
|
44
|
+
export default class PDFPage extends RectPath(Shape) {
|
|
45
|
+
constructor() {
|
|
46
|
+
super(...arguments);
|
|
47
|
+
this.scaleIndex = 0;
|
|
48
|
+
this.displayScale = 1;
|
|
49
|
+
this.offsetX = 0;
|
|
50
|
+
this.offsetY = 0;
|
|
51
|
+
this.pdfDoc = null;
|
|
52
|
+
this.canvas = document.createElement('canvas');
|
|
53
|
+
this.renderTask = null;
|
|
54
|
+
this.page = null;
|
|
55
|
+
this.documentSize = null;
|
|
56
|
+
this.position = { x: 0, y: 0 };
|
|
57
|
+
}
|
|
58
|
+
async ready() {
|
|
59
|
+
this.loadPDF();
|
|
60
|
+
}
|
|
61
|
+
dispose() {
|
|
62
|
+
super.dispose();
|
|
63
|
+
if (this.renderTask) {
|
|
64
|
+
this.renderTask.cancel();
|
|
65
|
+
}
|
|
66
|
+
this.pdfDoc = null;
|
|
67
|
+
this.canvas = null;
|
|
68
|
+
}
|
|
69
|
+
async loadPDF() {
|
|
70
|
+
const { file, page: pageNo = 1 } = this.state;
|
|
71
|
+
if (!file)
|
|
72
|
+
return;
|
|
73
|
+
try {
|
|
74
|
+
console.log(`📌 Loading PDF: ${file}`);
|
|
75
|
+
this.pdfDoc = await getDocument(file).promise;
|
|
76
|
+
const numPages = this.pdfDoc.numPages;
|
|
77
|
+
this.page = await this.pdfDoc.getPage(pageNo > numPages ? 1 : pageNo);
|
|
78
|
+
this.documentSize = this.page.getViewport({ scale: 1 });
|
|
79
|
+
this.fit();
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.error('🚨 Failed to load PDF:', error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
onchange(after, before) {
|
|
86
|
+
if ('file' in after || 'fit' in after || 'page' in after) {
|
|
87
|
+
this.loadPDF();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Adjusts the PDF display scale and offsets based on the fit mode.
|
|
92
|
+
*
|
|
93
|
+
* @async
|
|
94
|
+
* @method fit
|
|
95
|
+
* @memberof PdfPage
|
|
96
|
+
* @returns {Promise<void>}
|
|
97
|
+
*
|
|
98
|
+
* @description
|
|
99
|
+
* This method adjusts the display scale of the PDF page based on the `fit` mode specified in the component's state.
|
|
100
|
+
* It supports the following fit modes:
|
|
101
|
+
* - 'width': Scales the PDF to fit the width of the container.
|
|
102
|
+
* - 'height': Scales the PDF to fit the height of the container.
|
|
103
|
+
* - 'ratio': Scales the PDF to fit both the width and height of the container while maintaining the aspect ratio.
|
|
104
|
+
* - 'none': Displays the PDF at its original size.
|
|
105
|
+
*
|
|
106
|
+
* The method also calculates the appropriate offsets to center the PDF within the container when the fit mode is 'ratio'.
|
|
107
|
+
* Finally, it triggers the rendering of the PDF.
|
|
108
|
+
*/
|
|
109
|
+
async fit() {
|
|
110
|
+
if (!this.documentSize) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const { fit = 'none' } = this.state;
|
|
114
|
+
const { width, height } = this.bounds;
|
|
115
|
+
const viewport = this.documentSize;
|
|
116
|
+
switch (fit) {
|
|
117
|
+
case 'none':
|
|
118
|
+
this.displayScale = 1;
|
|
119
|
+
break;
|
|
120
|
+
case 'width':
|
|
121
|
+
this.displayScale = width / viewport.width;
|
|
122
|
+
break;
|
|
123
|
+
case 'height':
|
|
124
|
+
this.displayScale = height / viewport.height;
|
|
125
|
+
break;
|
|
126
|
+
case 'ratio':
|
|
127
|
+
this.displayScale = Math.min(width / viewport.width, height / viewport.height);
|
|
128
|
+
break;
|
|
129
|
+
default:
|
|
130
|
+
this.displayScale = 1;
|
|
131
|
+
}
|
|
132
|
+
this.scaleIndex = SCALE_LEVELS.findIndex(level => this.displayScale <= level);
|
|
133
|
+
if (this.scaleIndex === -1) {
|
|
134
|
+
this.scaleIndex = SCALE_LEVELS.length - 1;
|
|
135
|
+
}
|
|
136
|
+
if (fit === 'ratio') {
|
|
137
|
+
this.offsetX = (width - viewport.width * this.displayScale) / 2;
|
|
138
|
+
this.offsetY = (height - viewport.height * this.displayScale) / 2;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
this.offsetX = 0;
|
|
142
|
+
this.offsetY = 0;
|
|
143
|
+
}
|
|
144
|
+
this.renderPDF();
|
|
145
|
+
}
|
|
146
|
+
async renderPDF() {
|
|
147
|
+
if (!this.pdfDoc || !this.page || !this.documentSize) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const { width, height } = this.documentSize;
|
|
151
|
+
let scale = SCALE_LEVELS[this.scaleIndex];
|
|
152
|
+
let newWidth = Math.min(width * scale, MAX_CANVAS_SIZE);
|
|
153
|
+
let newHeight = Math.min(height * scale, MAX_CANVAS_SIZE);
|
|
154
|
+
if (newWidth === MAX_CANVAS_SIZE || newHeight === MAX_CANVAS_SIZE) {
|
|
155
|
+
const ratio = width / height;
|
|
156
|
+
if (ratio > 1) {
|
|
157
|
+
newHeight = newWidth / ratio;
|
|
158
|
+
}
|
|
159
|
+
const recalcScale = newHeight / height;
|
|
160
|
+
this.scaleIndex = SCALE_LEVELS.findIndex(level => recalcScale <= level) - 1;
|
|
161
|
+
scale = SCALE_LEVELS[this.scaleIndex];
|
|
162
|
+
newWidth = width * scale;
|
|
163
|
+
newHeight = height * scale;
|
|
164
|
+
}
|
|
165
|
+
// Create an `offscreenCanvas` to render in the background while maintaining the existing display
|
|
166
|
+
const offscreenCanvas = document.createElement('canvas');
|
|
167
|
+
offscreenCanvas.width = newWidth;
|
|
168
|
+
offscreenCanvas.height = newHeight;
|
|
169
|
+
const renderContext = {
|
|
170
|
+
canvasContext: offscreenCanvas.getContext('2d'),
|
|
171
|
+
viewport: this.page.getViewport({ scale })
|
|
172
|
+
};
|
|
173
|
+
if (this.renderTask) {
|
|
174
|
+
this.renderTask.cancel();
|
|
175
|
+
try {
|
|
176
|
+
await this.renderTask.promise;
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
console.warn('Previous render task was canceled.');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
this.renderTask = this.page.render(renderContext);
|
|
183
|
+
try {
|
|
184
|
+
await this.renderTask.promise;
|
|
185
|
+
// 🔹 Replace the existing canvas with the new canvas once rendering is complete
|
|
186
|
+
this.canvas = offscreenCanvas;
|
|
187
|
+
this.renderTask = null;
|
|
188
|
+
this.invalidate();
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
if (error instanceof Error && error.name !== 'RenderingCancelledException') {
|
|
192
|
+
console.error('Failed to render PDF:', error);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
render(ctx) {
|
|
197
|
+
var _a, _b;
|
|
198
|
+
super.render(ctx);
|
|
199
|
+
if (!this.canvas) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const { left, top } = this.bounds;
|
|
203
|
+
const { width, height } = this.canvas;
|
|
204
|
+
ctx.clip();
|
|
205
|
+
ctx.drawImage(this.canvas, left + this.offsetX, top + this.offsetY, (((_a = this.documentSize) === null || _a === void 0 ? void 0 : _a.width) || width) * this.displayScale, (((_b = this.documentSize) === null || _b === void 0 ? void 0 : _b.height) || height) * this.displayScale);
|
|
206
|
+
}
|
|
207
|
+
onwheel(e) {
|
|
208
|
+
e.preventDefault();
|
|
209
|
+
var { left, top } = this.bounds;
|
|
210
|
+
var { x, y } = this.transcoordC2S(e.offsetX, e.offsetY);
|
|
211
|
+
x -= left;
|
|
212
|
+
y -= top;
|
|
213
|
+
const zoomIn = e.deltaY < 0;
|
|
214
|
+
const zoomFactor = zoomIn ? 1.05 : 0.95;
|
|
215
|
+
const oldScale = this.displayScale;
|
|
216
|
+
this.displayScale = Math.min(Math.max(0.5, this.displayScale * zoomFactor), SCALE_LEVELS[SCALE_LEVELS.length - 1]);
|
|
217
|
+
const scaleLevel = SCALE_LEVELS.findIndex(level => this.displayScale <= level);
|
|
218
|
+
const newScaleIndex = scaleLevel === -1 ? SCALE_LEVELS.length - 1 : scaleLevel;
|
|
219
|
+
// Calculate zoom reference point (zoom in/out based on mouse position)
|
|
220
|
+
const scaleRatio = this.displayScale / oldScale;
|
|
221
|
+
this.offsetX = x - (x - this.offsetX) * scaleRatio;
|
|
222
|
+
this.offsetY = y - (y - this.offsetY) * scaleRatio;
|
|
223
|
+
this.invalidate();
|
|
224
|
+
if (newScaleIndex !== this.scaleIndex) {
|
|
225
|
+
this.scaleIndex = newScaleIndex;
|
|
226
|
+
this.renderPDF();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
ondragstart(e) {
|
|
230
|
+
this.position = this.transcoordC2S(e.offsetX, e.offsetY);
|
|
231
|
+
}
|
|
232
|
+
ondragmove(e) {
|
|
233
|
+
var { x, y } = this.transcoordC2S(e.offsetX, e.offsetY);
|
|
234
|
+
const dx = x - this.position.x;
|
|
235
|
+
const dy = y - this.position.y;
|
|
236
|
+
this.offsetX += dx;
|
|
237
|
+
this.offsetY += dy;
|
|
238
|
+
this.position = { x, y };
|
|
239
|
+
this.invalidate();
|
|
240
|
+
}
|
|
241
|
+
ondblclick(e) {
|
|
242
|
+
this.fit();
|
|
243
|
+
}
|
|
244
|
+
get nature() {
|
|
245
|
+
return NATURE;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
Component.register('pdf-page', PDFPage);
|
|
249
|
+
//# sourceMappingURL=pdf-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-page.js","sourceRoot":"","sources":["../src/pdf-page.ts"],"names":[],"mappings":"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","sourcesContent":["import { getDocument, GlobalWorkerOptions, PageViewport, PDFDocumentProxy, PDFPageProxy, RenderTask } from 'pdfjs-dist'\nimport { Component, Properties, RectPath, Shape } from '@hatiolab/things-scene'\n\nGlobalWorkerOptions.workerSrc = '/node_modules/pdfjs-dist/build/pdf.worker.min.mjs'\n\nconst NATURE = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'number',\n label: 'round',\n name: 'round',\n property: { min: 0 }\n },\n {\n type: 'attachment-selector',\n label: 'pdf-file',\n name: 'file',\n property: {\n displayField: 'fullpath',\n displayFullUrl: true,\n storageFilters: { type: Array, value: [{ name: 'category', value: 'application' }] },\n useUpload: true\n }\n },\n {\n type: 'number',\n label: 'pdf-page',\n name: 'page'\n },\n {\n type: 'select',\n label: 'pdf-fit',\n name: 'fit',\n property: {\n options: ['none', 'ratio', 'width', 'height']\n }\n }\n ],\n help: 'scene/component/pdf-viewer'\n}\n\nconst SCALE_LEVELS = [2, 4, 8, 16, 32]\nconst MAX_CANVAS_SIZE = 16000\n\nexport default class PDFPage extends RectPath(Shape) {\n private scaleIndex: number = 0\n private displayScale: number = 1\n private offsetX: number = 0\n private offsetY: number = 0\n private pdfDoc: PDFDocumentProxy | null = null\n private canvas: HTMLCanvasElement | null = document.createElement('canvas')\n private renderTask: RenderTask | null = null\n private page: PDFPageProxy | null = null\n private documentSize: PageViewport | null = null\n private position: { x: number; y: number } = { x: 0, y: 0 }\n\n async ready() {\n this.loadPDF()\n }\n\n dispose() {\n super.dispose()\n\n if (this.renderTask) {\n this.renderTask.cancel()\n }\n this.pdfDoc = null\n this.canvas = null\n }\n\n async loadPDF() {\n const { file, page: pageNo = 1 } = this.state\n if (!file) return\n\n try {\n console.log(`📌 Loading PDF: ${file}`)\n this.pdfDoc = await getDocument(file).promise\n\n const numPages = this.pdfDoc.numPages\n this.page = await this.pdfDoc.getPage(pageNo > numPages ? 1 : pageNo)\n this.documentSize = this.page.getViewport({ scale: 1 })\n\n this.fit()\n } catch (error) {\n console.error('🚨 Failed to load PDF:', error)\n }\n }\n\n onchange(after: Properties, before: Properties) {\n if ('file' in after || 'fit' in after || 'page' in after) {\n this.loadPDF()\n }\n }\n\n /**\n * Adjusts the PDF display scale and offsets based on the fit mode.\n *\n * @async\n * @method fit\n * @memberof PdfPage\n * @returns {Promise<void>}\n *\n * @description\n * This method adjusts the display scale of the PDF page based on the `fit` mode specified in the component's state.\n * It supports the following fit modes:\n * - 'width': Scales the PDF to fit the width of the container.\n * - 'height': Scales the PDF to fit the height of the container.\n * - 'ratio': Scales the PDF to fit both the width and height of the container while maintaining the aspect ratio.\n * - 'none': Displays the PDF at its original size.\n *\n * The method also calculates the appropriate offsets to center the PDF within the container when the fit mode is 'ratio'.\n * Finally, it triggers the rendering of the PDF.\n */\n async fit() {\n if (!this.documentSize) {\n return\n }\n\n const { fit = 'none' } = this.state\n const { width, height } = this.bounds\n const viewport = this.documentSize\n\n switch (fit) {\n case 'none':\n this.displayScale = 1\n break\n case 'width':\n this.displayScale = width / viewport.width\n break\n case 'height':\n this.displayScale = height / viewport.height\n break\n case 'ratio':\n this.displayScale = Math.min(width / viewport.width, height / viewport.height)\n break\n default:\n this.displayScale = 1\n }\n\n this.scaleIndex = SCALE_LEVELS.findIndex(level => this.displayScale <= level)\n if (this.scaleIndex === -1) {\n this.scaleIndex = SCALE_LEVELS.length - 1\n }\n\n if (fit === 'ratio') {\n this.offsetX = (width - viewport.width * this.displayScale) / 2\n this.offsetY = (height - viewport.height * this.displayScale) / 2\n } else {\n this.offsetX = 0\n this.offsetY = 0\n }\n\n this.renderPDF()\n }\n\n async renderPDF() {\n if (!this.pdfDoc || !this.page || !this.documentSize) {\n return\n }\n\n const { width, height } = this.documentSize\n\n let scale = SCALE_LEVELS[this.scaleIndex]\n\n let newWidth = Math.min(width * scale, MAX_CANVAS_SIZE)\n let newHeight = Math.min(height * scale, MAX_CANVAS_SIZE)\n\n if (newWidth === MAX_CANVAS_SIZE || newHeight === MAX_CANVAS_SIZE) {\n const ratio = width / height\n if (ratio > 1) {\n newHeight = newWidth / ratio\n }\n\n const recalcScale = newHeight / height\n\n this.scaleIndex = SCALE_LEVELS.findIndex(level => recalcScale <= level) - 1\n scale = SCALE_LEVELS[this.scaleIndex]\n\n newWidth = width * scale\n newHeight = height * scale\n }\n\n // Create an `offscreenCanvas` to render in the background while maintaining the existing display\n const offscreenCanvas = document.createElement('canvas')\n offscreenCanvas.width = newWidth\n offscreenCanvas.height = newHeight\n\n const renderContext = {\n canvasContext: offscreenCanvas.getContext('2d')!,\n viewport: this.page.getViewport({ scale })\n }\n\n if (this.renderTask) {\n this.renderTask.cancel()\n try {\n await this.renderTask.promise\n } catch (error) {\n console.warn('Previous render task was canceled.')\n }\n }\n\n this.renderTask = this.page.render(renderContext)\n\n try {\n await this.renderTask.promise\n\n // 🔹 Replace the existing canvas with the new canvas once rendering is complete\n this.canvas = offscreenCanvas\n this.renderTask = null\n\n this.invalidate()\n } catch (error) {\n if (error instanceof Error && error.name !== 'RenderingCancelledException') {\n console.error('Failed to render PDF:', error)\n }\n }\n }\n\n render(ctx: CanvasRenderingContext2D) {\n super.render(ctx)\n\n if (!this.canvas) {\n return\n }\n\n const { left, top } = this.bounds\n const { width, height } = this.canvas\n\n ctx.clip()\n ctx.drawImage(\n this.canvas,\n left + this.offsetX,\n top + this.offsetY,\n (this.documentSize?.width || width) * this.displayScale,\n (this.documentSize?.height || height) * this.displayScale\n )\n }\n\n onwheel(e: WheelEvent) {\n e.preventDefault()\n var { left, top } = this.bounds\n var { x, y } = this.transcoordC2S(e.offsetX, e.offsetY)\n x -= left\n y -= top\n\n const zoomIn = e.deltaY < 0\n const zoomFactor = zoomIn ? 1.05 : 0.95\n const oldScale = this.displayScale\n\n this.displayScale = Math.min(Math.max(0.5, this.displayScale * zoomFactor), SCALE_LEVELS[SCALE_LEVELS.length - 1])\n\n const scaleLevel = SCALE_LEVELS.findIndex(level => this.displayScale <= level)\n const newScaleIndex = scaleLevel === -1 ? SCALE_LEVELS.length - 1 : scaleLevel\n\n // Calculate zoom reference point (zoom in/out based on mouse position)\n const scaleRatio = this.displayScale / oldScale\n this.offsetX = x - (x - this.offsetX) * scaleRatio\n this.offsetY = y - (y - this.offsetY) * scaleRatio\n\n this.invalidate()\n\n if (newScaleIndex !== this.scaleIndex) {\n this.scaleIndex = newScaleIndex\n this.renderPDF()\n }\n }\n\n ondragstart(e: MouseEvent) {\n this.position = this.transcoordC2S(e.offsetX, e.offsetY)\n }\n\n ondragmove(e: MouseEvent) {\n var { x, y } = this.transcoordC2S(e.offsetX, e.offsetY)\n const dx = x - this.position.x\n const dy = y - this.position.y\n this.offsetX += dx\n this.offsetY += dy\n this.position = { x, y }\n this.invalidate()\n }\n\n ondblclick(e: MouseEvent) {\n this.fit()\n }\n\n get nature() {\n return NATURE\n }\n}\n\nComponent.register('pdf-page', PDFPage)\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
type: string;
|
|
3
|
+
description: string;
|
|
4
|
+
icon: string;
|
|
5
|
+
group: string;
|
|
6
|
+
model: {
|
|
7
|
+
type: string;
|
|
8
|
+
left: number;
|
|
9
|
+
top: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
strokeStyle: string;
|
|
13
|
+
lineDash: string;
|
|
14
|
+
lineWidth: number;
|
|
15
|
+
};
|
|
16
|
+
}[];
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,eAAe,CAAA;AAEnC,eAAe,CAAC,OAAO,CAAC,CAAA","sourcesContent":["import pdfPage from './pdf-page.js'\n\nexport default [pdfPage]\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
type: string;
|
|
3
|
+
description: string;
|
|
4
|
+
icon: string;
|
|
5
|
+
group: string;
|
|
6
|
+
model: {
|
|
7
|
+
type: string;
|
|
8
|
+
left: number;
|
|
9
|
+
top: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
strokeStyle: string;
|
|
13
|
+
lineDash: string;
|
|
14
|
+
lineWidth: number;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const icon = new URL('../../icons/icon-pdf-page.png', import.meta.url).href;
|
|
2
|
+
export default {
|
|
3
|
+
type: 'pdf-page',
|
|
4
|
+
description: 'pdf page viewer',
|
|
5
|
+
icon,
|
|
6
|
+
group: 'etc',
|
|
7
|
+
model: {
|
|
8
|
+
type: 'pdf-page',
|
|
9
|
+
left: 100,
|
|
10
|
+
top: 100,
|
|
11
|
+
width: 800,
|
|
12
|
+
height: 600,
|
|
13
|
+
strokeStyle: '#000',
|
|
14
|
+
lineDash: 'solid',
|
|
15
|
+
lineWidth: 1
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=pdf-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-page.js","sourceRoot":"","sources":["../../src/templates/pdf-page.ts"],"names":[],"mappings":"AAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,+BAA+B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;AAE3E,eAAe;IACb,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,iBAAiB;IAC9B,IAAI;IACJ,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE;QACL,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,GAAG;QACT,GAAG,EAAE,GAAG;QACR,KAAK,EAAE,GAAG;QACV,MAAM,EAAE,GAAG;QACX,WAAW,EAAE,MAAM;QACnB,QAAQ,EAAE,OAAO;QACjB,SAAS,EAAE,CAAC;KACb;CACF,CAAA","sourcesContent":["const icon = new URL('../../icons/icon-pdf-page.png', import.meta.url).href\n\nexport default {\n type: 'pdf-page',\n description: 'pdf page viewer',\n icon,\n group: 'etc',\n model: {\n type: 'pdf-page',\n left: 100,\n top: 100,\n width: 800,\n height: 600,\n strokeStyle: '#000',\n lineDash: 'solid',\n lineWidth: 1\n }\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## PDF ページ
|
|
2
|
+
|
|
3
|
+
PDF ページコンポーネントを使用すると、シーン内で PDF ドキュメントを表示およびインタラクションすることができます。
|
|
4
|
+
|
|
5
|
+
### プロパティ
|
|
6
|
+
|
|
7
|
+
- **round** - コンポーネントの角の丸みを設定します(最小値:0)
|
|
8
|
+
- **ファイル** - 表示する PDF ファイルのパス
|
|
9
|
+
- **ページ** - 表示するページ番号(1 から開始)
|
|
10
|
+
- **合わせる** - PDF をコンポーネントに合わせる方法:
|
|
11
|
+
- **none** - 原寸大
|
|
12
|
+
- **ratio** - アスペクト比を維持しながらフィット
|
|
13
|
+
- **width** - 幅に合わせる
|
|
14
|
+
- **height** - 高さに合わせる
|
|
15
|
+
|
|
16
|
+
### インタラクション
|
|
17
|
+
|
|
18
|
+
- **マウスホイール** - ズームイン/アウト
|
|
19
|
+
- **ドラッグ** - PDF ビューのパン
|
|
20
|
+
- **ダブルクリック** - フィットモードにリセット
|
|
21
|
+
|
|
22
|
+
### 注意事項
|
|
23
|
+
|
|
24
|
+
- 大きな PDF ファイルは高品質でレンダリングするのに時間がかかる場合があります
|
|
25
|
+
- このコンポーネントは大きなドキュメントのメモリ最適化を自動的に処理します
|
|
26
|
+
- ブラウザの制限を防ぐため、最大キャンバスサイズは 16000 ピクセルに制限されています
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## PDF 페이지
|
|
2
|
+
|
|
3
|
+
PDF 페이지 컴포넌트는 씬(Scene)에서 PDF 문서를 표시하고 상호 작용할 수 있게 해줍니다.
|
|
4
|
+
|
|
5
|
+
### 속성
|
|
6
|
+
|
|
7
|
+
- **round** - 컴포넌트 모서리의 둥글기 (최소값: 0)
|
|
8
|
+
- **파일** - 표시할 PDF 파일 경로
|
|
9
|
+
- **페이지** - 표시할 페이지 번호 (1부터 시작)
|
|
10
|
+
- **맞춤** - PDF가 컴포넌트에 맞는 방식:
|
|
11
|
+
- **none** - 원본 크기
|
|
12
|
+
- **ratio** - 종횡비를 유지하며 크기에 맞춤
|
|
13
|
+
- **width** - 너비에 맞춤
|
|
14
|
+
- **height** - 높이에 맞춤
|
|
15
|
+
|
|
16
|
+
### 상호 작용
|
|
17
|
+
|
|
18
|
+
- **마우스 휠** - 확대/축소
|
|
19
|
+
- **드래그** - PDF 뷰 이동
|
|
20
|
+
- **더블 클릭** - 맞춤 모드로 재설정
|
|
21
|
+
|
|
22
|
+
### 참고 사항
|
|
23
|
+
|
|
24
|
+
- 대용량 PDF 파일은 고품질로 렌더링하는 데 시간이 걸릴 수 있습니다
|
|
25
|
+
- 이 컴포넌트는 대용량 문서에 대한 메모리 최적화를 자동으로 처리합니다
|
|
26
|
+
- 최대 캔버스 크기는 브라우저 제한을 방지하기 위해 16000픽셀로 제한됩니다
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## PDF Page
|
|
2
|
+
|
|
3
|
+
The PDF Page component allows you to display and interact with PDF documents in your scene.
|
|
4
|
+
|
|
5
|
+
### Properties
|
|
6
|
+
|
|
7
|
+
- **round** - Rounds the corners of the component (min: 0)
|
|
8
|
+
- **file** - Path to the PDF file to display
|
|
9
|
+
- **page** - Page number to display (starts from 1)
|
|
10
|
+
- **fit** - How the PDF should fit in the component:
|
|
11
|
+
- **none** - Original size
|
|
12
|
+
- **ratio** - Scaled to fit while maintaining aspect ratio
|
|
13
|
+
- **width** - Scaled to fit width
|
|
14
|
+
- **height** - Scaled to fit height
|
|
15
|
+
|
|
16
|
+
### Interactions
|
|
17
|
+
|
|
18
|
+
- **Mouse wheel** - Zoom in/out
|
|
19
|
+
- **Drag** - Pan the PDF view
|
|
20
|
+
- **Double-click** - Reset to fit mode
|
|
21
|
+
|
|
22
|
+
### Notes
|
|
23
|
+
|
|
24
|
+
- Large PDF files may take time to render at high quality
|
|
25
|
+
- The component automatically handles memory optimization for large documents
|
|
26
|
+
- Maximum canvas size is limited to 16000 pixels to prevent browser limitations
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## Halaman PDF
|
|
2
|
+
|
|
3
|
+
Komponen Halaman PDF membolehkan anda memaparkan dan berinteraksi dengan dokumen PDF dalam paparan anda.
|
|
4
|
+
|
|
5
|
+
### Ciri-ciri
|
|
6
|
+
|
|
7
|
+
- **round** - Membulatkan sudut komponen (min: 0)
|
|
8
|
+
- **fail** - Laluan ke fail PDF untuk dipaparkan
|
|
9
|
+
- **page** - Nombor halaman untuk dipaparkan (bermula dari 1)
|
|
10
|
+
- **fit** - Bagaimana PDF harus muat dalam komponen:
|
|
11
|
+
- **none** - Saiz asal
|
|
12
|
+
- **ratio** - Diskalakan untuk muat sambil mengekalkan nisbah aspek
|
|
13
|
+
- **width** - Diskalakan untuk muat lebar
|
|
14
|
+
- **height** - Diskalakan untuk muat tinggi
|
|
15
|
+
|
|
16
|
+
### Interaksi
|
|
17
|
+
|
|
18
|
+
- **Roda tetikus** - Zum masuk/keluar
|
|
19
|
+
- **Seret** - Pan pandangan PDF
|
|
20
|
+
- **Klik dua kali** - Set semula ke mod muat
|
|
21
|
+
|
|
22
|
+
### Nota
|
|
23
|
+
|
|
24
|
+
- Fail PDF besar mungkin mengambil masa untuk dirender pada kualiti tinggi
|
|
25
|
+
- Komponen ini secara automatik mengendalikan pengoptimuman memori untuk dokumen besar
|
|
26
|
+
- Saiz kanvas maksimum terhad kepada 16000 piksel untuk mencegah had pelayar
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## PDF 页面
|
|
2
|
+
|
|
3
|
+
PDF 页面组件允许您在场景中显示和交互 PDF 文档。
|
|
4
|
+
|
|
5
|
+
### 属性
|
|
6
|
+
|
|
7
|
+
- **round** - 组件角的圆角度(最小值:0)
|
|
8
|
+
- **文件** - 要显示的 PDF 文件路径
|
|
9
|
+
- **页面** - 要显示的页码(从 1 开始)
|
|
10
|
+
- **匹配** - PDF 在组件中的适应方式:
|
|
11
|
+
- **none** - 原始大小
|
|
12
|
+
- **ratio** - 保持宽高比缩放以适应
|
|
13
|
+
- **width** - 适应宽度
|
|
14
|
+
- **height** - 适应高度
|
|
15
|
+
|
|
16
|
+
### 交互
|
|
17
|
+
|
|
18
|
+
- **鼠标滚轮** - 放大/缩小
|
|
19
|
+
- **拖动** - 平移 PDF 视图
|
|
20
|
+
- **双击** - 重置为适应模式
|
|
21
|
+
|
|
22
|
+
### 注意事项
|
|
23
|
+
|
|
24
|
+
- 大型 PDF 文件可能需要时间以高质量渲染
|
|
25
|
+
- 该组件自动处理大型文档的内存优化
|
|
26
|
+
- 最大画布大小限制为 16000 像素,以防止浏览器限制
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@operato/scene-pdf",
|
|
3
|
+
"description": "pdf component for operato-scene",
|
|
4
|
+
"author": "heartyoh",
|
|
5
|
+
"version": "9.0.0-beta.12",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/index.js",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"things-scene": true,
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public",
|
|
13
|
+
"@oprato:registry": "https://registry.npmjs.org"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/things-scene/operato-scene.git",
|
|
18
|
+
"directory": "packages/pdf"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"serve": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"things-factory-dev\"",
|
|
22
|
+
"serve:dev": "npm run serve",
|
|
23
|
+
"start": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wds\"",
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"prepublish": "tsc",
|
|
26
|
+
"lint": "eslint --ext .ts,.html . --ignore-path .gitignore && prettier \"**/*.ts\" --check --ignore-path .gitignore",
|
|
27
|
+
"format": "eslint --ext .ts,.html . --fix --ignore-path .gitignore && prettier \"**/*.ts\" --write --ignore-path .gitignore",
|
|
28
|
+
"migration": "things-factory-migration"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@hatiolab/things-scene": "^9.0.0-beta",
|
|
32
|
+
"lit": "^3.1.2",
|
|
33
|
+
"pdfjs-dist": "^4.10.38"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@hatiolab/prettier-config": "^1.0.0",
|
|
37
|
+
"@things-factory/builder": "^9.0.0-beta",
|
|
38
|
+
"@things-factory/operato-board": "^9.0.0-beta",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
|
40
|
+
"@typescript-eslint/parser": "^4.33.0",
|
|
41
|
+
"@web/dev-server": "^0.1.28",
|
|
42
|
+
"concurrently": "^8.0.1",
|
|
43
|
+
"eslint": "^9.18.0",
|
|
44
|
+
"eslint-config-prettier": "^10.0.1",
|
|
45
|
+
"husky": "^8.0.3",
|
|
46
|
+
"lint-staged": "^13.2.2",
|
|
47
|
+
"prettier": "^2.4.1",
|
|
48
|
+
"tslib": "^2.3.1",
|
|
49
|
+
"typescript": "^5.0.4"
|
|
50
|
+
},
|
|
51
|
+
"prettier": "@hatiolab/prettier-config",
|
|
52
|
+
"husky": {
|
|
53
|
+
"hooks": {
|
|
54
|
+
"pre-commit": "lint-staged"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"lint-staged": {
|
|
58
|
+
"*.ts": [
|
|
59
|
+
"eslint --fix",
|
|
60
|
+
"prettier --write"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"gitHead": "4e5088777eb5187e7f8d3c5d5ffeb633a3802341"
|
|
64
|
+
}
|