@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 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,2 @@
1
+ declare const _default: never[];
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ export default [];
2
+ //# sourceMappingURL=index.js.map
@@ -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"]}
@@ -0,0 +1,3 @@
1
+ import PDFPage from './pdf-page.js';
2
+ declare const _default: (typeof PDFPage)[];
3
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import PDFPage from './pdf-page.js';
2
+ export default [PDFPage];
3
+ //# sourceMappingURL=index.js.map
@@ -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 {};
@@ -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,3 @@
1
+ import pdfPage from './pdf-page.js';
2
+ export default [pdfPage];
3
+ //# sourceMappingURL=index.js.map
@@ -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
+ }
@@ -0,0 +1,7 @@
1
+ import editors from './dist/editors/index.js'
2
+ import templates from './dist/templates/index.js'
3
+
4
+ export default {
5
+ templates,
6
+ editors
7
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "component.pdf-pag": "pdf page",
3
+ "label.pdf-file": "file",
4
+ "label.pdf-page": "page",
5
+ "label.pdf-fit": "fit"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "component.pdf-pag": "pdf page",
3
+ "label.pdf-file": "ファイル",
4
+ "label.pdf-page": "ページ",
5
+ "label.pdf-fit": "合わせる"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "component.pdf-pag": "pdf page",
3
+ "label.pdf-file": "파일",
4
+ "label.pdf-page": "페이지",
5
+ "label.pdf-fit": "맞춤"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "component.pdf-pag": "pdf page",
3
+ "label.pdf-file": "fail",
4
+ "label.pdf-page": "page",
5
+ "label.pdf-fit": "fit"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "component.pdf-pag": "pdf page",
3
+ "label.pdf-file": "文件",
4
+ "label.pdf-page": "页面",
5
+ "label.pdf-fit": "匹配"
6
+ }