@forgeroute/ui 0.3.7 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/forgeroute-ui-pdf.mjs +582 -0
- package/fesm2022/forgeroute-ui-pdf.mjs.map +1 -0
- package/fesm2022/forgeroute-ui.mjs +13370 -10365
- package/fesm2022/forgeroute-ui.mjs.map +1 -1
- package/package.json +10 -2
- package/types/forgeroute-ui-pdf.d.ts +206 -0
- package/types/forgeroute-ui.d.ts +1166 -145
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
import { isPlatformBrowser } from "@angular/common";
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, InjectionToken, Injector, PLATFORM_ID, afterNextRender, computed, effect, inject, input, output, signal, untracked } from "@angular/core";
|
|
4
|
+
const PDF_VIEWER_WORKER_SRC = new InjectionToken("PDF_VIEWER_WORKER_SRC", {
|
|
5
|
+
providedIn: "root",
|
|
6
|
+
factory: () => ""
|
|
7
|
+
});
|
|
8
|
+
const DEFAULT_MAX_WIDTH = 700;
|
|
9
|
+
const DEFAULT_FIELD_HEIGHT = 14;
|
|
10
|
+
const MAX_CANVAS_PIXELS = 16e6;
|
|
11
|
+
const MAX_TOTAL_CANVAS_PIXELS = 48e6;
|
|
12
|
+
const WORKER_MISSING = "PDF worker is not configured.";
|
|
13
|
+
var PdfViewerComponent = class PdfViewerComponent {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.src = input(null, ...ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []);
|
|
16
|
+
this.data = input(null, ...ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []);
|
|
17
|
+
this.httpHeaders = input({}, ...ngDevMode ? [{ debugName: "httpHeaders" }] : /* istanbul ignore next */ []);
|
|
18
|
+
this.withCredentials = input(false, ...ngDevMode ? [{ debugName: "withCredentials" }] : /* istanbul ignore next */ []);
|
|
19
|
+
this.workerSrc = input("", ...ngDevMode ? [{ debugName: "workerSrc" }] : /* istanbul ignore next */ []);
|
|
20
|
+
this.maxPageWidth = input(DEFAULT_MAX_WIDTH, ...ngDevMode ? [{ debugName: "maxPageWidth" }] : /* istanbul ignore next */ []);
|
|
21
|
+
this.pixelRatio = input(null, ...ngDevMode ? [{ debugName: "pixelRatio" }] : /* istanbul ignore next */ []);
|
|
22
|
+
this.fields = input([], ...ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []);
|
|
23
|
+
this.ariaLabel = input("", ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
|
|
24
|
+
this.loadingText = input("Loading document…", ...ngDevMode ? [{ debugName: "loadingText" }] : /* istanbul ignore next */ []);
|
|
25
|
+
this.errorText = input("Failed to load document.", ...ngDevMode ? [{ debugName: "errorText" }] : /* istanbul ignore next */ []);
|
|
26
|
+
this.loaded = output();
|
|
27
|
+
this.loadFailed = output();
|
|
28
|
+
this.pagesRendered = output();
|
|
29
|
+
this.status = signal("idle", ...ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []);
|
|
30
|
+
this.pageSizes = signal([], ...ngDevMode ? [{ debugName: "pageSizes" }] : /* istanbul ignore next */ []);
|
|
31
|
+
this.containerWidth = signal(0, ...ngDevMode ? [{ debugName: "containerWidth" }] : /* istanbul ignore next */ []);
|
|
32
|
+
this.customError = signal("", ...ngDevMode ? [{ debugName: "customError" }] : /* istanbul ignore next */ []);
|
|
33
|
+
this.errorMessage = computed(() => this.customError() || this.errorText(), ...ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []);
|
|
34
|
+
this.drawKey = computed(() => this.views().map((v) => v.canvasWidth + "x" + v.canvasHeight).join("|"), ...ngDevMode ? [{ debugName: "drawKey" }] : /* istanbul ignore next */ []);
|
|
35
|
+
this.effectiveWidth = computed(() => this.widthFor(this.containerWidth()), ...ngDevMode ? [{ debugName: "effectiveWidth" }] : /* istanbul ignore next */ []);
|
|
36
|
+
this.views = computed(() => {
|
|
37
|
+
const sizes = this.pageSizes();
|
|
38
|
+
const cssWidth = this.effectiveWidth();
|
|
39
|
+
const ratio = this.resolvedRatio();
|
|
40
|
+
const byPage = /* @__PURE__ */ new Map();
|
|
41
|
+
for (const f of this.fields()) {
|
|
42
|
+
if (!Number.isInteger(f.page) || f.page < 1 || f.page > sizes.length) continue;
|
|
43
|
+
const list = byPage.get(f.page) ?? [];
|
|
44
|
+
list.push(f);
|
|
45
|
+
byPage.set(f.page, list);
|
|
46
|
+
}
|
|
47
|
+
const base = sizes.map((size) => {
|
|
48
|
+
const scale = cssWidth / size.width;
|
|
49
|
+
const cssHeight = size.height * scale;
|
|
50
|
+
return {
|
|
51
|
+
scale,
|
|
52
|
+
cssHeight,
|
|
53
|
+
pageRatio: Math.min(ratio, Math.sqrt(MAX_CANVAS_PIXELS / (cssWidth * cssHeight)))
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
let factor = 1;
|
|
57
|
+
const bitmaps = () => base.map((b) => {
|
|
58
|
+
const r = Math.max(Math.min(b.pageRatio, 1), b.pageRatio * factor);
|
|
59
|
+
return {
|
|
60
|
+
w: Math.floor(cssWidth * r),
|
|
61
|
+
h: Math.floor(b.cssHeight * r)
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
let sized = bitmaps();
|
|
65
|
+
for (let i = 0; i < 6; i++) {
|
|
66
|
+
const total = sized.reduce((sum, b) => sum + b.w * b.h, 0);
|
|
67
|
+
if (total <= MAX_TOTAL_CANVAS_PIXELS) break;
|
|
68
|
+
factor *= Math.sqrt(MAX_TOTAL_CANVAS_PIXELS / total);
|
|
69
|
+
sized = bitmaps();
|
|
70
|
+
}
|
|
71
|
+
return sizes.map((size, i) => {
|
|
72
|
+
const { scale, cssHeight } = base[i];
|
|
73
|
+
const fields = (byPage.get(i + 1) ?? []).map((f) => {
|
|
74
|
+
const h = f.height ?? DEFAULT_FIELD_HEIGHT;
|
|
75
|
+
const left = f.x / size.width * 100;
|
|
76
|
+
return {
|
|
77
|
+
id: f.id,
|
|
78
|
+
label: f.label,
|
|
79
|
+
tone: f.tone ?? "blue",
|
|
80
|
+
left,
|
|
81
|
+
top: (size.height - f.y - h) / size.height * 100,
|
|
82
|
+
width: f.width == null ? null : f.width / size.width * 100,
|
|
83
|
+
maxWidth: Math.max(0, 100 - left),
|
|
84
|
+
height: h / size.height * 100,
|
|
85
|
+
fontPx: Math.max(9, h * scale * .7)
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
number: i + 1,
|
|
90
|
+
cssWidth,
|
|
91
|
+
cssHeight,
|
|
92
|
+
canvasWidth: sized[i].w,
|
|
93
|
+
canvasHeight: sized[i].h,
|
|
94
|
+
fields
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
}, ...ngDevMode ? [{ debugName: "views" }] : /* istanbul ignore next */ []);
|
|
98
|
+
this.host = inject(ElementRef);
|
|
99
|
+
this.injector = inject(Injector);
|
|
100
|
+
this.tokenWorkerSrc = inject(PDF_VIEWER_WORKER_SRC);
|
|
101
|
+
this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
102
|
+
this.headersKey = computed(() => JSON.stringify(this.httpHeaders()), ...ngDevMode ? [{ debugName: "headersKey" }] : /* istanbul ignore next */ []);
|
|
103
|
+
this.loadToken = 0;
|
|
104
|
+
this.drawToken = 0;
|
|
105
|
+
this.doc = null;
|
|
106
|
+
this.loadingTask = null;
|
|
107
|
+
this.pageProxies = [];
|
|
108
|
+
this.renderTasks = [];
|
|
109
|
+
this.observer = null;
|
|
110
|
+
this.frame = 0;
|
|
111
|
+
this.lastDrawKey = "";
|
|
112
|
+
effect(() => {
|
|
113
|
+
this.src();
|
|
114
|
+
this.data();
|
|
115
|
+
this.headersKey();
|
|
116
|
+
this.withCredentials();
|
|
117
|
+
this.workerSrc();
|
|
118
|
+
if (!this.isBrowser) return;
|
|
119
|
+
untracked(() => void this.startLoad());
|
|
120
|
+
});
|
|
121
|
+
effect(() => {
|
|
122
|
+
const key = this.drawKey();
|
|
123
|
+
untracked(() => {
|
|
124
|
+
if (this.status() === "ready" && key !== this.lastDrawKey) this.scheduleDraw();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
if (this.isBrowser && typeof ResizeObserver !== "undefined") {
|
|
128
|
+
this.observer = new ResizeObserver(() => this.onResize());
|
|
129
|
+
this.observer.observe(this.host.nativeElement);
|
|
130
|
+
}
|
|
131
|
+
inject(DestroyRef).onDestroy(() => {
|
|
132
|
+
this.loadToken++;
|
|
133
|
+
this.drawToken++;
|
|
134
|
+
this.observer?.disconnect();
|
|
135
|
+
if (this.frame && typeof cancelAnimationFrame === "function") cancelAnimationFrame(this.frame);
|
|
136
|
+
this.teardown();
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
loadPdfJs() {
|
|
140
|
+
return import("pdfjs-dist");
|
|
141
|
+
}
|
|
142
|
+
resolvedRatio() {
|
|
143
|
+
const explicit = this.pixelRatio();
|
|
144
|
+
if (explicit != null && explicit > 0) return explicit;
|
|
145
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
146
|
+
return Math.min(Math.max(dpr, 1), 3);
|
|
147
|
+
}
|
|
148
|
+
widthFor(container) {
|
|
149
|
+
const max = this.maxPageWidth() > 0 ? this.maxPageWidth() : DEFAULT_MAX_WIDTH;
|
|
150
|
+
return container > 0 ? Math.min(max, container) : max;
|
|
151
|
+
}
|
|
152
|
+
async startLoad() {
|
|
153
|
+
const token = ++this.loadToken;
|
|
154
|
+
this.drawToken++;
|
|
155
|
+
this.teardown();
|
|
156
|
+
this.pageSizes.set([]);
|
|
157
|
+
this.customError.set("");
|
|
158
|
+
const data = this.data();
|
|
159
|
+
const src = this.src();
|
|
160
|
+
if (data == null && !src) {
|
|
161
|
+
this.status.set("idle");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
this.containerWidth.set(this.host.nativeElement.clientWidth);
|
|
165
|
+
this.status.set("loading");
|
|
166
|
+
try {
|
|
167
|
+
const pdfjs = await this.loadPdfJs();
|
|
168
|
+
if (token !== this.loadToken) return;
|
|
169
|
+
const worker = this.workerSrc() || this.tokenWorkerSrc;
|
|
170
|
+
if (worker) pdfjs.GlobalWorkerOptions.workerSrc = worker;
|
|
171
|
+
else if (!pdfjs.GlobalWorkerOptions.workerSrc) {
|
|
172
|
+
this.fail(/* @__PURE__ */ new Error(WORKER_MISSING), WORKER_MISSING);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const params = data != null ? { data: data instanceof Uint8Array ? data.slice() : new Uint8Array(data.slice(0)) } : { url: src };
|
|
176
|
+
if (data == null) {
|
|
177
|
+
const headers = this.httpHeaders();
|
|
178
|
+
if (Object.keys(headers).length > 0) params["httpHeaders"] = headers;
|
|
179
|
+
if (this.withCredentials()) params["withCredentials"] = true;
|
|
180
|
+
}
|
|
181
|
+
const task = pdfjs.getDocument(params);
|
|
182
|
+
this.loadingTask = task;
|
|
183
|
+
const doc = await task.promise;
|
|
184
|
+
if (token !== this.loadToken) {
|
|
185
|
+
this.destroyDoc(doc);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
this.doc = doc;
|
|
189
|
+
const proxies = [];
|
|
190
|
+
const sizes = [];
|
|
191
|
+
for (let i = 1; i <= doc.numPages; i++) {
|
|
192
|
+
const page = await doc.getPage(i);
|
|
193
|
+
if (token !== this.loadToken) return;
|
|
194
|
+
const vp = page.getViewport({ scale: 1 });
|
|
195
|
+
if (!(Number.isFinite(vp.width) && Number.isFinite(vp.height) && vp.width > 0 && vp.height > 0)) throw new Error("invalid page size");
|
|
196
|
+
proxies.push(page);
|
|
197
|
+
sizes.push({
|
|
198
|
+
width: vp.width,
|
|
199
|
+
height: vp.height
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
this.pageProxies = proxies;
|
|
203
|
+
this.containerWidth.set(this.host.nativeElement.clientWidth);
|
|
204
|
+
this.pageSizes.set(sizes);
|
|
205
|
+
this.status.set("ready");
|
|
206
|
+
this.loaded.emit({
|
|
207
|
+
pageCount: sizes.length,
|
|
208
|
+
pages: sizes.map((s) => ({ ...s })),
|
|
209
|
+
document: doc
|
|
210
|
+
});
|
|
211
|
+
this.scheduleDraw();
|
|
212
|
+
} catch (err) {
|
|
213
|
+
if (token !== this.loadToken) return;
|
|
214
|
+
this.fail(err);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
fail(err, message = "") {
|
|
218
|
+
this.loadToken++;
|
|
219
|
+
this.drawToken++;
|
|
220
|
+
this.teardown();
|
|
221
|
+
this.pageSizes.set([]);
|
|
222
|
+
this.customError.set(message);
|
|
223
|
+
this.status.set("error");
|
|
224
|
+
this.loadFailed.emit(err);
|
|
225
|
+
}
|
|
226
|
+
scheduleDraw() {
|
|
227
|
+
const id = ++this.drawToken;
|
|
228
|
+
this.lastDrawKey = this.drawKey();
|
|
229
|
+
this.cancelRenders();
|
|
230
|
+
afterNextRender(() => void this.draw(id), { injector: this.injector });
|
|
231
|
+
}
|
|
232
|
+
async draw(id) {
|
|
233
|
+
const token = this.loadToken;
|
|
234
|
+
const stale = () => id !== this.drawToken || token !== this.loadToken;
|
|
235
|
+
this.cancelRenders();
|
|
236
|
+
const views = this.views();
|
|
237
|
+
const canvases = Array.from(this.host.nativeElement.querySelectorAll("canvas.pv-canvas"));
|
|
238
|
+
const sizes = this.pageSizes();
|
|
239
|
+
const scales = [];
|
|
240
|
+
try {
|
|
241
|
+
for (let i = 0; i < views.length; i++) {
|
|
242
|
+
if (stale()) return;
|
|
243
|
+
const canvas = canvases[i];
|
|
244
|
+
const page = this.pageProxies[i];
|
|
245
|
+
if (!canvas || !page || !canvas.getContext("2d")) throw new Error("canvas unavailable");
|
|
246
|
+
const cssScale = views[i].cssWidth / sizes[i].width;
|
|
247
|
+
scales.push(cssScale);
|
|
248
|
+
const viewport = page.getViewport({ scale: views[i].canvasWidth / sizes[i].width });
|
|
249
|
+
const task = page.render({
|
|
250
|
+
canvas,
|
|
251
|
+
viewport
|
|
252
|
+
});
|
|
253
|
+
this.renderTasks.push(task);
|
|
254
|
+
await task.promise;
|
|
255
|
+
}
|
|
256
|
+
} catch (err) {
|
|
257
|
+
if (stale() || err?.name === "RenderingCancelledException") return;
|
|
258
|
+
this.fail(err);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (stale()) return;
|
|
262
|
+
this.pagesRendered.emit({
|
|
263
|
+
pageCount: views.length,
|
|
264
|
+
scale: scales[0] ?? 1,
|
|
265
|
+
pageWidths: views.map((v) => v.cssWidth)
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
onResize() {
|
|
269
|
+
if (this.frame || typeof requestAnimationFrame !== "function") return;
|
|
270
|
+
this.frame = requestAnimationFrame(() => {
|
|
271
|
+
this.frame = 0;
|
|
272
|
+
const before = this.effectiveWidth();
|
|
273
|
+
this.containerWidth.set(this.host.nativeElement.clientWidth);
|
|
274
|
+
if (this.effectiveWidth() !== before && this.status() === "ready") this.scheduleDraw();
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
cancelRenders() {
|
|
278
|
+
for (const t of this.renderTasks) try {
|
|
279
|
+
t.cancel?.();
|
|
280
|
+
} catch {}
|
|
281
|
+
this.renderTasks = [];
|
|
282
|
+
}
|
|
283
|
+
teardown() {
|
|
284
|
+
this.cancelRenders();
|
|
285
|
+
const task = this.loadingTask;
|
|
286
|
+
this.loadingTask = null;
|
|
287
|
+
if (task) try {
|
|
288
|
+
Promise.resolve(task.destroy?.()).catch(() => void 0);
|
|
289
|
+
} catch {}
|
|
290
|
+
const doc = this.doc;
|
|
291
|
+
this.doc = null;
|
|
292
|
+
this.pageProxies = [];
|
|
293
|
+
if (doc) this.destroyDoc(doc);
|
|
294
|
+
}
|
|
295
|
+
destroyDoc(doc) {
|
|
296
|
+
try {
|
|
297
|
+
Promise.resolve(doc.destroy()).catch(() => void 0);
|
|
298
|
+
} catch {}
|
|
299
|
+
}
|
|
300
|
+
static {
|
|
301
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
302
|
+
minVersion: "12.0.0",
|
|
303
|
+
version: "22.2.2",
|
|
304
|
+
ngImport: i0,
|
|
305
|
+
type: PdfViewerComponent,
|
|
306
|
+
deps: [],
|
|
307
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
static {
|
|
311
|
+
this.ɵcmp = i0.ɵɵngDeclareComponent({
|
|
312
|
+
minVersion: "17.0.0",
|
|
313
|
+
version: "22.2.2",
|
|
314
|
+
type: PdfViewerComponent,
|
|
315
|
+
isStandalone: true,
|
|
316
|
+
selector: "ui-pdf-viewer",
|
|
317
|
+
inputs: {
|
|
318
|
+
src: {
|
|
319
|
+
classPropertyName: "src",
|
|
320
|
+
publicName: "src",
|
|
321
|
+
isSignal: true,
|
|
322
|
+
isRequired: false,
|
|
323
|
+
transformFunction: null
|
|
324
|
+
},
|
|
325
|
+
data: {
|
|
326
|
+
classPropertyName: "data",
|
|
327
|
+
publicName: "data",
|
|
328
|
+
isSignal: true,
|
|
329
|
+
isRequired: false,
|
|
330
|
+
transformFunction: null
|
|
331
|
+
},
|
|
332
|
+
httpHeaders: {
|
|
333
|
+
classPropertyName: "httpHeaders",
|
|
334
|
+
publicName: "httpHeaders",
|
|
335
|
+
isSignal: true,
|
|
336
|
+
isRequired: false,
|
|
337
|
+
transformFunction: null
|
|
338
|
+
},
|
|
339
|
+
withCredentials: {
|
|
340
|
+
classPropertyName: "withCredentials",
|
|
341
|
+
publicName: "withCredentials",
|
|
342
|
+
isSignal: true,
|
|
343
|
+
isRequired: false,
|
|
344
|
+
transformFunction: null
|
|
345
|
+
},
|
|
346
|
+
workerSrc: {
|
|
347
|
+
classPropertyName: "workerSrc",
|
|
348
|
+
publicName: "workerSrc",
|
|
349
|
+
isSignal: true,
|
|
350
|
+
isRequired: false,
|
|
351
|
+
transformFunction: null
|
|
352
|
+
},
|
|
353
|
+
maxPageWidth: {
|
|
354
|
+
classPropertyName: "maxPageWidth",
|
|
355
|
+
publicName: "maxPageWidth",
|
|
356
|
+
isSignal: true,
|
|
357
|
+
isRequired: false,
|
|
358
|
+
transformFunction: null
|
|
359
|
+
},
|
|
360
|
+
pixelRatio: {
|
|
361
|
+
classPropertyName: "pixelRatio",
|
|
362
|
+
publicName: "pixelRatio",
|
|
363
|
+
isSignal: true,
|
|
364
|
+
isRequired: false,
|
|
365
|
+
transformFunction: null
|
|
366
|
+
},
|
|
367
|
+
fields: {
|
|
368
|
+
classPropertyName: "fields",
|
|
369
|
+
publicName: "fields",
|
|
370
|
+
isSignal: true,
|
|
371
|
+
isRequired: false,
|
|
372
|
+
transformFunction: null
|
|
373
|
+
},
|
|
374
|
+
ariaLabel: {
|
|
375
|
+
classPropertyName: "ariaLabel",
|
|
376
|
+
publicName: "ariaLabel",
|
|
377
|
+
isSignal: true,
|
|
378
|
+
isRequired: false,
|
|
379
|
+
transformFunction: null
|
|
380
|
+
},
|
|
381
|
+
loadingText: {
|
|
382
|
+
classPropertyName: "loadingText",
|
|
383
|
+
publicName: "loadingText",
|
|
384
|
+
isSignal: true,
|
|
385
|
+
isRequired: false,
|
|
386
|
+
transformFunction: null
|
|
387
|
+
},
|
|
388
|
+
errorText: {
|
|
389
|
+
classPropertyName: "errorText",
|
|
390
|
+
publicName: "errorText",
|
|
391
|
+
isSignal: true,
|
|
392
|
+
isRequired: false,
|
|
393
|
+
transformFunction: null
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
outputs: {
|
|
397
|
+
loaded: "loaded",
|
|
398
|
+
loadFailed: "loadFailed",
|
|
399
|
+
pagesRendered: "pagesRendered"
|
|
400
|
+
},
|
|
401
|
+
ngImport: i0,
|
|
402
|
+
template: `
|
|
403
|
+
<div class="pv-root" [attr.role]="ariaLabel() ? 'region' : null" [attr.aria-label]="ariaLabel() || null"
|
|
404
|
+
[attr.aria-busy]="status() === 'loading'">
|
|
405
|
+
<div class="pv-live" role="status" aria-live="polite">{{ status() === 'loading' ? loadingText() : '' }}</div>
|
|
406
|
+
@switch (status()) {
|
|
407
|
+
@case ('loading') { <div class="pv-state pv-loading" aria-hidden="true">{{ loadingText() }}</div> }
|
|
408
|
+
@case ('error') { <div class="pv-state pv-error" role="alert">{{ errorMessage() }}</div> }
|
|
409
|
+
@case ('ready') {
|
|
410
|
+
<div class="pv-pages">
|
|
411
|
+
@for (p of views(); track p.number) {
|
|
412
|
+
<div class="pv-page" [style.width.px]="p.cssWidth">
|
|
413
|
+
<canvas class="pv-canvas" role="img" [attr.aria-label]="'Page ' + p.number + ' of ' + views().length"
|
|
414
|
+
[attr.width]="p.canvasWidth" [attr.height]="p.canvasHeight"></canvas>
|
|
415
|
+
@for (f of p.fields; track $index) {
|
|
416
|
+
<div class="pv-field pv-tone-{{ f.tone }}"
|
|
417
|
+
[style.left.%]="f.left" [style.top.%]="f.top" [style.width.%]="f.width" [style.max-width.%]="f.maxWidth"
|
|
418
|
+
[style.height.%]="f.height" [style.font-size.px]="f.fontPx">
|
|
419
|
+
<span class="pv-field-label">{{ f.label }}</span>
|
|
420
|
+
</div>
|
|
421
|
+
}
|
|
422
|
+
</div>
|
|
423
|
+
}
|
|
424
|
+
</div>
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
</div>
|
|
428
|
+
`,
|
|
429
|
+
isInline: true,
|
|
430
|
+
styles: [":host{display:block;width:100%}.pv-root{position:relative}.pv-live{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pv-state{display:flex;align-items:center;justify-content:center;width:100%;min-height:12rem;padding:0 16px;text-align:center;font-size:.8125rem;line-height:1.4;overflow-wrap:anywhere;box-sizing:border-box}.pv-loading{color:#64748b}.pv-error{color:#dc2626}.pv-pages{display:flex;flex-direction:column;gap:16px;width:100%;max-width:100%}.pv-page{position:relative;margin:0 auto;max-width:100%}.pv-canvas{display:block;width:100%;height:auto;background:#fff;border-radius:2px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.pv-field{position:absolute;display:flex;align-items:center;box-sizing:border-box;padding:0 4px;overflow:hidden;pointer-events:none;border:1px solid;border-radius:2px;-webkit-user-select:none;user-select:none}.pv-field-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1}.pv-tone-blue{background:#dbeafe;border-color:#93c5fd;color:#1d4ed8}.pv-tone-green{background:#dcfce7;border-color:#86efac;color:#15803d}.pv-tone-amber{background:#fef3c7;border-color:#fcd34d;color:#92400e}.pv-tone-red{background:#fee2e2;border-color:#fca5a5;color:#b91c1c}.pv-tone-slate{background:#f1f5f9;border-color:#cbd5e1;color:#334155}\n"],
|
|
431
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
436
|
+
minVersion: "12.0.0",
|
|
437
|
+
version: "22.2.2",
|
|
438
|
+
ngImport: i0,
|
|
439
|
+
type: PdfViewerComponent,
|
|
440
|
+
decorators: [{
|
|
441
|
+
type: Component,
|
|
442
|
+
args: [{
|
|
443
|
+
selector: "ui-pdf-viewer",
|
|
444
|
+
standalone: true,
|
|
445
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
446
|
+
template: `
|
|
447
|
+
<div class="pv-root" [attr.role]="ariaLabel() ? 'region' : null" [attr.aria-label]="ariaLabel() || null"
|
|
448
|
+
[attr.aria-busy]="status() === 'loading'">
|
|
449
|
+
<div class="pv-live" role="status" aria-live="polite">{{ status() === 'loading' ? loadingText() : '' }}</div>
|
|
450
|
+
@switch (status()) {
|
|
451
|
+
@case ('loading') { <div class="pv-state pv-loading" aria-hidden="true">{{ loadingText() }}</div> }
|
|
452
|
+
@case ('error') { <div class="pv-state pv-error" role="alert">{{ errorMessage() }}</div> }
|
|
453
|
+
@case ('ready') {
|
|
454
|
+
<div class="pv-pages">
|
|
455
|
+
@for (p of views(); track p.number) {
|
|
456
|
+
<div class="pv-page" [style.width.px]="p.cssWidth">
|
|
457
|
+
<canvas class="pv-canvas" role="img" [attr.aria-label]="'Page ' + p.number + ' of ' + views().length"
|
|
458
|
+
[attr.width]="p.canvasWidth" [attr.height]="p.canvasHeight"></canvas>
|
|
459
|
+
@for (f of p.fields; track $index) {
|
|
460
|
+
<div class="pv-field pv-tone-{{ f.tone }}"
|
|
461
|
+
[style.left.%]="f.left" [style.top.%]="f.top" [style.width.%]="f.width" [style.max-width.%]="f.maxWidth"
|
|
462
|
+
[style.height.%]="f.height" [style.font-size.px]="f.fontPx">
|
|
463
|
+
<span class="pv-field-label">{{ f.label }}</span>
|
|
464
|
+
</div>
|
|
465
|
+
}
|
|
466
|
+
</div>
|
|
467
|
+
}
|
|
468
|
+
</div>
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
</div>
|
|
472
|
+
`,
|
|
473
|
+
styles: [":host{display:block;width:100%}.pv-root{position:relative}.pv-live{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pv-state{display:flex;align-items:center;justify-content:center;width:100%;min-height:12rem;padding:0 16px;text-align:center;font-size:.8125rem;line-height:1.4;overflow-wrap:anywhere;box-sizing:border-box}.pv-loading{color:#64748b}.pv-error{color:#dc2626}.pv-pages{display:flex;flex-direction:column;gap:16px;width:100%;max-width:100%}.pv-page{position:relative;margin:0 auto;max-width:100%}.pv-canvas{display:block;width:100%;height:auto;background:#fff;border-radius:2px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.pv-field{position:absolute;display:flex;align-items:center;box-sizing:border-box;padding:0 4px;overflow:hidden;pointer-events:none;border:1px solid;border-radius:2px;-webkit-user-select:none;user-select:none}.pv-field-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1}.pv-tone-blue{background:#dbeafe;border-color:#93c5fd;color:#1d4ed8}.pv-tone-green{background:#dcfce7;border-color:#86efac;color:#15803d}.pv-tone-amber{background:#fef3c7;border-color:#fcd34d;color:#92400e}.pv-tone-red{background:#fee2e2;border-color:#fca5a5;color:#b91c1c}.pv-tone-slate{background:#f1f5f9;border-color:#cbd5e1;color:#334155}\n"]
|
|
474
|
+
}]
|
|
475
|
+
}],
|
|
476
|
+
ctorParameters: () => [],
|
|
477
|
+
propDecorators: {
|
|
478
|
+
src: [{
|
|
479
|
+
type: i0.Input,
|
|
480
|
+
args: [{
|
|
481
|
+
isSignal: true,
|
|
482
|
+
alias: "src",
|
|
483
|
+
required: false
|
|
484
|
+
}]
|
|
485
|
+
}],
|
|
486
|
+
data: [{
|
|
487
|
+
type: i0.Input,
|
|
488
|
+
args: [{
|
|
489
|
+
isSignal: true,
|
|
490
|
+
alias: "data",
|
|
491
|
+
required: false
|
|
492
|
+
}]
|
|
493
|
+
}],
|
|
494
|
+
httpHeaders: [{
|
|
495
|
+
type: i0.Input,
|
|
496
|
+
args: [{
|
|
497
|
+
isSignal: true,
|
|
498
|
+
alias: "httpHeaders",
|
|
499
|
+
required: false
|
|
500
|
+
}]
|
|
501
|
+
}],
|
|
502
|
+
withCredentials: [{
|
|
503
|
+
type: i0.Input,
|
|
504
|
+
args: [{
|
|
505
|
+
isSignal: true,
|
|
506
|
+
alias: "withCredentials",
|
|
507
|
+
required: false
|
|
508
|
+
}]
|
|
509
|
+
}],
|
|
510
|
+
workerSrc: [{
|
|
511
|
+
type: i0.Input,
|
|
512
|
+
args: [{
|
|
513
|
+
isSignal: true,
|
|
514
|
+
alias: "workerSrc",
|
|
515
|
+
required: false
|
|
516
|
+
}]
|
|
517
|
+
}],
|
|
518
|
+
maxPageWidth: [{
|
|
519
|
+
type: i0.Input,
|
|
520
|
+
args: [{
|
|
521
|
+
isSignal: true,
|
|
522
|
+
alias: "maxPageWidth",
|
|
523
|
+
required: false
|
|
524
|
+
}]
|
|
525
|
+
}],
|
|
526
|
+
pixelRatio: [{
|
|
527
|
+
type: i0.Input,
|
|
528
|
+
args: [{
|
|
529
|
+
isSignal: true,
|
|
530
|
+
alias: "pixelRatio",
|
|
531
|
+
required: false
|
|
532
|
+
}]
|
|
533
|
+
}],
|
|
534
|
+
fields: [{
|
|
535
|
+
type: i0.Input,
|
|
536
|
+
args: [{
|
|
537
|
+
isSignal: true,
|
|
538
|
+
alias: "fields",
|
|
539
|
+
required: false
|
|
540
|
+
}]
|
|
541
|
+
}],
|
|
542
|
+
ariaLabel: [{
|
|
543
|
+
type: i0.Input,
|
|
544
|
+
args: [{
|
|
545
|
+
isSignal: true,
|
|
546
|
+
alias: "ariaLabel",
|
|
547
|
+
required: false
|
|
548
|
+
}]
|
|
549
|
+
}],
|
|
550
|
+
loadingText: [{
|
|
551
|
+
type: i0.Input,
|
|
552
|
+
args: [{
|
|
553
|
+
isSignal: true,
|
|
554
|
+
alias: "loadingText",
|
|
555
|
+
required: false
|
|
556
|
+
}]
|
|
557
|
+
}],
|
|
558
|
+
errorText: [{
|
|
559
|
+
type: i0.Input,
|
|
560
|
+
args: [{
|
|
561
|
+
isSignal: true,
|
|
562
|
+
alias: "errorText",
|
|
563
|
+
required: false
|
|
564
|
+
}]
|
|
565
|
+
}],
|
|
566
|
+
loaded: [{
|
|
567
|
+
type: i0.Output,
|
|
568
|
+
args: ["loaded"]
|
|
569
|
+
}],
|
|
570
|
+
loadFailed: [{
|
|
571
|
+
type: i0.Output,
|
|
572
|
+
args: ["loadFailed"]
|
|
573
|
+
}],
|
|
574
|
+
pagesRendered: [{
|
|
575
|
+
type: i0.Output,
|
|
576
|
+
args: ["pagesRendered"]
|
|
577
|
+
}]
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
export { PDF_VIEWER_WORKER_SRC, PdfViewerComponent };
|
|
581
|
+
|
|
582
|
+
//# sourceMappingURL=forgeroute-ui-pdf.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forgeroute-ui-pdf.mjs","names":[],"sources":["../../../projects/forgeroute-ui/pdf/src/pdf-viewer/pdf-viewer.component.ts"],"sourcesContent":["import { isPlatformBrowser } from '@angular/common';\nimport {\n PLATFORM_ID, Component, ChangeDetectionStrategy, DestroyRef, ElementRef, InjectionToken, Injector, afterNextRender, computed, effect,\n inject, input, output, signal, untracked,\n} from '@angular/core';\nimport type { PDFDocumentProxy, PDFPageProxy } from 'pdfjs-dist';\n\n/** Where pdf.js finds its worker script. Provide it once in the app (`{ provide: PDF_VIEWER_WORKER_SRC, useValue: '/assets/pdf.worker.min.mjs' }`). */\nexport const PDF_VIEWER_WORKER_SRC = new InjectionToken<string>('PDF_VIEWER_WORKER_SRC', { providedIn: 'root', factory: () => '' });\n\n/** Colour of an overlay badge. */\nexport type PdfViewerTone = 'blue' | 'green' | 'amber' | 'red' | 'slate';\n\n/** A labelled box drawn over a page. Positions are PDF points with the origin at the page's bottom-left corner. */\nexport interface PdfViewerField {\n id: string;\n /** 1-based page number; a field on a page that does not exist is ignored. */\n page: number;\n /** Bottom-left corner of the box, in PDF points. */\n x: number;\n y: number;\n /** Size in PDF points. Without a width the box fits its label; the default height is 14. */\n width?: number;\n height?: number;\n label: string;\n tone?: PdfViewerTone;\n}\n\nexport interface PdfViewerLoadedEvent {\n pageCount: number;\n /** Every page's size in PDF points at scale 1. */\n pages: { width: number; height: number }[];\n /** The loaded pdf.js document, so the host can read text content. The viewer destroys it when it is replaced or the viewer goes away. */\n document: PDFDocumentProxy;\n}\n\nexport interface PdfViewerRenderedEvent {\n pageCount: number;\n /** CSS px per PDF point of the first page. */\n scale: number;\n /** Displayed (CSS px) width of every page. */\n pageWidths: number[];\n}\n\ntype PdfJsModule = typeof import('pdfjs-dist');\ntype Status = 'idle' | 'loading' | 'ready' | 'error';\n\ninterface PageView {\n number: number;\n cssWidth: number;\n cssHeight: number;\n canvasWidth: number;\n canvasHeight: number;\n fields: FieldView[];\n}\ninterface FieldView {\n id: string; label: string; tone: PdfViewerTone;\n left: number; top: number; width: number | null; maxWidth: number; height: number; fontPx: number;\n}\n\nconst DEFAULT_MAX_WIDTH = 700;\nconst DEFAULT_FIELD_HEIGHT = 14;\n/** Most pixels one page's canvas may have; Safari (iOS especially) refuses or blanks bigger ones. */\nconst MAX_CANVAS_PIXELS = 16_000_000;\n/** Most pixels all canvases together may have; iOS Safari limits total canvas memory. */\nconst MAX_TOTAL_CANVAS_PIXELS = 48_000_000;\nconst WORKER_MISSING = 'PDF worker is not configured.';\n\n/**\n * Renders every page of a PDF into a canvas (crisp on high-density screens), with optional labelled boxes overlaid in PDF coordinates.\n * Needs `pdfjs-dist` (loaded on first use, so it stays out of bundles that never show a PDF).\n *\n * <ui-pdf-viewer [data]=\"buffer()\" [fields]=\"badges()\" ariaLabel=\"Contract preview\" (loaded)=\"onLoaded($event)\" />\n * <ui-pdf-viewer src=\"/files/contract.pdf\" [httpHeaders]=\"{ Authorization: 'Bearer ' + token }\" />\n *\n * - `src` / `data`: a URL, or the bytes (`data` wins). The bytes are copied, so your buffer stays usable.\n * - `workerSrc` or the `PDF_VIEWER_WORKER_SRC` token: the pdf.js worker URL. Without either the viewer shows \"PDF worker is not configured.\"\n * - `maxPageWidth` (default 700): pages are drawn this wide, or the container's width when narrower; never larger.\n * - `pixelRatio`: canvas pixels per CSS pixel; default is the screen's ratio between 1 and 3.\n * - `fields`: badges positioned in PDF points (origin bottom-left); they scale with the page.\n * - `loaded` / `pagesRendered` / `loadFailed`: see the event types. A new `src` / `data` replaces the document; a slow older load never paints.\n * A page that fails to draw after `loaded` also emits `loadFailed`, shows the error state and destroys the document that `loaded` handed to the host.\n * - A page's canvas never exceeds 16,000,000 pixels (Safari limit); the pixel ratio is lowered for such a page, its CSS size is unchanged.\n * - All canvases together never exceed 48,000,000 pixels (iOS Safari limits total canvas memory): a long document is drawn at a lower\n * density, the same for every page and never below 1 pixel per CSS pixel. CSS sizes are unchanged.\n * - `httpHeaders` and `withCredentials` apply to `src` only; they are not used when `data` is given.\n * - `fields[].id` is only a display / test hook; duplicates are tolerated. `httpHeaders` is compared by content, but a stable reference is still preferred.\n * - The worker-missing message is fixed text and ignores `errorText`, because it is a setup problem for the developer.\n * - Needs pdf.js 5 (`pdfjs-dist` >= 5), which needs Safari 17.4+; the legacy pdf.js build is not supported by this component.\n * - The public typings reference `pdfjs-dist` types: apps that type-check the library without `pdfjs-dist` installed need `skipLibCheck` or the\n * package (the same trade-off as `@forgeroute/ui/charts` and chart.js).\n */\n@Component({\n selector: 'ui-pdf-viewer',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"pv-root\" [attr.role]=\"ariaLabel() ? 'region' : null\" [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-busy]=\"status() === 'loading'\">\n <div class=\"pv-live\" role=\"status\" aria-live=\"polite\">{{ status() === 'loading' ? loadingText() : '' }}</div>\n @switch (status()) {\n @case ('loading') { <div class=\"pv-state pv-loading\" aria-hidden=\"true\">{{ loadingText() }}</div> }\n @case ('error') { <div class=\"pv-state pv-error\" role=\"alert\">{{ errorMessage() }}</div> }\n @case ('ready') {\n <div class=\"pv-pages\">\n @for (p of views(); track p.number) {\n <div class=\"pv-page\" [style.width.px]=\"p.cssWidth\">\n <canvas class=\"pv-canvas\" role=\"img\" [attr.aria-label]=\"'Page ' + p.number + ' of ' + views().length\"\n [attr.width]=\"p.canvasWidth\" [attr.height]=\"p.canvasHeight\"></canvas>\n @for (f of p.fields; track $index) {\n <div class=\"pv-field pv-tone-{{ f.tone }}\"\n [style.left.%]=\"f.left\" [style.top.%]=\"f.top\" [style.width.%]=\"f.width\" [style.max-width.%]=\"f.maxWidth\"\n [style.height.%]=\"f.height\" [style.font-size.px]=\"f.fontPx\">\n <span class=\"pv-field-label\">{{ f.label }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n `,\n styles: [`\n :host { display: block; width: 100%; }\n .pv-root { position: relative; }\n .pv-live { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }\n .pv-state { display: flex; align-items: center; justify-content: center; width: 100%; min-height: 12rem; padding: 0 16px; text-align: center;\n font-size: 0.8125rem; line-height: 1.4; overflow-wrap: anywhere; box-sizing: border-box; }\n .pv-loading { color: #64748b; }\n .pv-error { color: #dc2626; }\n .pv-pages { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 100%; }\n .pv-page { position: relative; margin: 0 auto; max-width: 100%; }\n .pv-canvas { display: block; width: 100%; height: auto; background: #fff; border-radius: 2px;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1); }\n .pv-field { position: absolute; display: flex; align-items: center; box-sizing: border-box; padding: 0 4px; overflow: hidden;\n pointer-events: none; border: 1px solid; border-radius: 2px; -webkit-user-select: none; user-select: none; }\n .pv-field-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1; }\n .pv-tone-blue { background: #dbeafe; border-color: #93c5fd; color: #1d4ed8; }\n .pv-tone-green { background: #dcfce7; border-color: #86efac; color: #15803d; }\n .pv-tone-amber { background: #fef3c7; border-color: #fcd34d; color: #92400e; }\n .pv-tone-red { background: #fee2e2; border-color: #fca5a5; color: #b91c1c; }\n .pv-tone-slate { background: #f1f5f9; border-color: #cbd5e1; color: #334155; }\n `],\n})\nexport class PdfViewerComponent {\n /** PDF URL. Ignored while `data` is set. */\n readonly src = input<string | null>(null);\n /** PDF bytes. Wins over `src`. */\n readonly data = input<ArrayBuffer | Uint8Array | null>(null);\n /** Request headers for `src`. Changes are detected by content, but pass a stable reference when you can. */\n readonly httpHeaders = input<Record<string, string>>({});\n readonly withCredentials = input(false);\n /** pdf.js worker URL; falls back to the `PDF_VIEWER_WORKER_SRC` token. */\n readonly workerSrc = input('');\n /** Widest a page is drawn, in CSS px. */\n readonly maxPageWidth = input(DEFAULT_MAX_WIDTH);\n /** Canvas pixels per CSS pixel; null = the screen's ratio, limited to 1..3. */\n readonly pixelRatio = input<number | null>(null);\n readonly fields = input<PdfViewerField[]>([]);\n /** Accessible name of the viewer. */\n readonly ariaLabel = input('');\n readonly loadingText = input('Loading document…');\n readonly errorText = input('Failed to load document.');\n\n readonly loaded = output<PdfViewerLoadedEvent>();\n readonly loadFailed = output<unknown>();\n readonly pagesRendered = output<PdfViewerRenderedEvent>();\n\n protected readonly status = signal<Status>('idle');\n private readonly pageSizes = signal<{ width: number; height: number }[]>([]);\n private readonly containerWidth = signal(0);\n private readonly customError = signal('');\n protected readonly errorMessage = computed(() => this.customError() || this.errorText());\n\n /** Changes exactly when some canvas bitmap changes size (and so is cleared). */\n private readonly drawKey = computed(() => this.views().map(v => v.canvasWidth + 'x' + v.canvasHeight).join('|'));\n private readonly effectiveWidth = computed(() => this.widthFor(this.containerWidth()));\n protected readonly views = computed((): PageView[] => {\n const sizes = this.pageSizes();\n const cssWidth = this.effectiveWidth();\n const ratio = this.resolvedRatio();\n const byPage = new Map<number, PdfViewerField[]>();\n for (const f of this.fields()) {\n if (!Number.isInteger(f.page) || f.page < 1 || f.page > sizes.length) continue;\n const list = byPage.get(f.page) ?? [];\n list.push(f);\n byPage.set(f.page, list);\n }\n const base = sizes.map(size => {\n const scale = cssWidth / size.width;\n const cssHeight = size.height * scale;\n // lower the density for a page whose bitmap would pass the canvas limit; the CSS size stays\n const pageRatio = Math.min(ratio, Math.sqrt(MAX_CANVAS_PIXELS / (cssWidth * cssHeight)));\n return { scale, cssHeight, pageRatio };\n });\n // a total budget for long documents: shrink every page's density by the same factor, but never below 1 (or below a cap-lowered ratio)\n let factor = 1;\n const bitmaps = () => base.map(b => {\n const r = Math.max(Math.min(b.pageRatio, 1), b.pageRatio * factor);\n return { w: Math.floor(cssWidth * r), h: Math.floor(b.cssHeight * r) };\n });\n let sized = bitmaps();\n for (let i = 0; i < 6; i++) {\n const total = sized.reduce((sum, b) => sum + b.w * b.h, 0);\n if (total <= MAX_TOTAL_CANVAS_PIXELS) break;\n factor *= Math.sqrt(MAX_TOTAL_CANVAS_PIXELS / total);\n sized = bitmaps();\n }\n return sizes.map((size, i) => {\n const { scale, cssHeight } = base[i];\n const fields = (byPage.get(i + 1) ?? []).map((f): FieldView => {\n const h = f.height ?? DEFAULT_FIELD_HEIGHT;\n const left = (f.x / size.width) * 100;\n return {\n id: f.id, label: f.label, tone: f.tone ?? 'blue',\n left, top: ((size.height - f.y - h) / size.height) * 100,\n width: f.width == null ? null : (f.width / size.width) * 100,\n maxWidth: Math.max(0, 100 - left),\n height: (h / size.height) * 100,\n fontPx: Math.max(9, h * scale * 0.7),\n };\n });\n return { number: i + 1, cssWidth, cssHeight, canvasWidth: sized[i].w, canvasHeight: sized[i].h, fields };\n });\n });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n private readonly tokenWorkerSrc = inject(PDF_VIEWER_WORKER_SRC);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly headersKey = computed(() => JSON.stringify(this.httpHeaders()));\n\n /** Bumped by every new load, replacement and destroy; an async step whose token no longer matches stops. */\n private loadToken = 0;\n /** Bumped by every (re)draw so only the newest draw paints. */\n private drawToken = 0;\n private doc: PDFDocumentProxy | null = null;\n private loadingTask: { destroy?: () => unknown } | null = null;\n private pageProxies: PDFPageProxy[] = [];\n private renderTasks: { cancel?: () => void }[] = [];\n private observer: ResizeObserver | null = null;\n private frame = 0;\n private lastDrawKey = '';\n\n constructor() {\n effect(() => {\n this.src(); this.data(); this.headersKey(); this.withCredentials(); this.workerSrc();\n if (!this.isBrowser) return; // nothing to load or draw on the server\n untracked(() => void this.startLoad());\n });\n // Whatever resizes the canvases (maxPageWidth, pixelRatio) clears them, so a changed bitmap size needs a redraw. Draws the code\n // already scheduled record their key in scheduleDraw(), so this only fires for changes nothing else handled.\n effect(() => {\n const key = this.drawKey();\n untracked(() => { if (this.status() === 'ready' && key !== this.lastDrawKey) this.scheduleDraw(); });\n });\n if (this.isBrowser && typeof ResizeObserver !== 'undefined') {\n this.observer = new ResizeObserver(() => this.onResize());\n this.observer.observe(this.host.nativeElement);\n }\n inject(DestroyRef).onDestroy(() => {\n this.loadToken++;\n this.drawToken++;\n this.observer?.disconnect();\n if (this.frame && typeof cancelAnimationFrame === 'function') cancelAnimationFrame(this.frame);\n this.teardown();\n });\n }\n\n /** Test seam: loads pdf.js on first use so apps that never show a PDF do not bundle or fetch it. */\n protected loadPdfJs(): Promise<PdfJsModule> {\n return import('pdfjs-dist');\n }\n\n private resolvedRatio(): number {\n const explicit = this.pixelRatio();\n if (explicit != null && explicit > 0) return explicit;\n const dpr = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;\n return Math.min(Math.max(dpr, 1), 3);\n }\n\n private widthFor(container: number): number {\n const max = this.maxPageWidth() > 0 ? this.maxPageWidth() : DEFAULT_MAX_WIDTH;\n return container > 0 ? Math.min(max, container) : max;\n }\n\n private async startLoad(): Promise<void> {\n const token = ++this.loadToken;\n this.drawToken++;\n this.teardown();\n this.pageSizes.set([]);\n this.customError.set('');\n const data = this.data();\n const src = this.src();\n if (data == null && !src) { this.status.set('idle'); return; }\n this.containerWidth.set(this.host.nativeElement.clientWidth);\n this.status.set('loading');\n try {\n const pdfjs = await this.loadPdfJs();\n if (token !== this.loadToken) return;\n const worker = this.workerSrc() || this.tokenWorkerSrc;\n if (worker) pdfjs.GlobalWorkerOptions.workerSrc = worker;\n else if (!pdfjs.GlobalWorkerOptions.workerSrc) { this.fail(new Error(WORKER_MISSING), WORKER_MISSING); return; }\n\n const params: Record<string, unknown> = data != null\n ? { data: data instanceof Uint8Array ? data.slice() : new Uint8Array(data.slice(0)) } // pdf.js detaches what it is given\n : { url: src };\n if (data == null) { // request options only make sense for a URL\n const headers = this.httpHeaders();\n if (Object.keys(headers).length > 0) params['httpHeaders'] = headers;\n if (this.withCredentials()) params['withCredentials'] = true;\n }\n const task = pdfjs.getDocument(params as unknown as Parameters<PdfJsModule['getDocument']>[0]);\n this.loadingTask = task;\n const doc = await task.promise;\n if (token !== this.loadToken) { this.destroyDoc(doc); return; }\n this.doc = doc;\n\n const proxies: PDFPageProxy[] = [];\n const sizes: { width: number; height: number }[] = [];\n for (let i = 1; i <= doc.numPages; i++) {\n const page = await doc.getPage(i);\n if (token !== this.loadToken) return;\n const vp = page.getViewport({ scale: 1 });\n if (!(Number.isFinite(vp.width) && Number.isFinite(vp.height) && vp.width > 0 && vp.height > 0)) throw new Error('invalid page size');\n proxies.push(page);\n sizes.push({ width: vp.width, height: vp.height });\n }\n this.pageProxies = proxies;\n this.containerWidth.set(this.host.nativeElement.clientWidth); // the container may have changed while the file loaded\n this.pageSizes.set(sizes);\n this.status.set('ready');\n this.loaded.emit({ pageCount: sizes.length, pages: sizes.map(s => ({ ...s })), document: doc });\n this.scheduleDraw();\n } catch (err) {\n if (token !== this.loadToken) return;\n this.fail(err);\n }\n }\n\n private fail(err: unknown, message = ''): void {\n this.loadToken++; // nothing still in flight may paint over the error\n this.drawToken++;\n this.teardown();\n this.pageSizes.set([]);\n this.customError.set(message);\n this.status.set('error');\n this.loadFailed.emit(err);\n }\n\n private scheduleDraw(): void {\n const id = ++this.drawToken;\n this.lastDrawKey = this.drawKey();\n this.cancelRenders(); // a still-running paint must not land in canvases about to be resized\n afterNextRender(() => void this.draw(id), { injector: this.injector });\n }\n\n private async draw(id: number): Promise<void> {\n const token = this.loadToken;\n const stale = () => id !== this.drawToken || token !== this.loadToken;\n this.cancelRenders();\n const views = this.views();\n const canvases = Array.from(this.host.nativeElement.querySelectorAll<HTMLCanvasElement>('canvas.pv-canvas'));\n const sizes = this.pageSizes();\n const scales: number[] = [];\n try {\n for (let i = 0; i < views.length; i++) {\n if (stale()) return;\n const canvas = canvases[i];\n const page = this.pageProxies[i];\n if (!canvas || !page || !canvas.getContext('2d')) throw new Error('canvas unavailable');\n const cssScale = views[i].cssWidth / sizes[i].width;\n scales.push(cssScale);\n const viewport = page.getViewport({ scale: (views[i].canvasWidth / sizes[i].width) });\n const task = page.render({ canvas, viewport });\n this.renderTasks.push(task);\n await task.promise;\n }\n } catch (err) {\n if (stale() || (err as { name?: string } | null)?.name === 'RenderingCancelledException') return;\n this.fail(err);\n return;\n }\n if (stale()) return;\n this.pagesRendered.emit({ pageCount: views.length, scale: scales[0] ?? 1, pageWidths: views.map(v => v.cssWidth) });\n }\n\n private onResize(): void {\n if (this.frame || typeof requestAnimationFrame !== 'function') return;\n this.frame = requestAnimationFrame(() => {\n this.frame = 0;\n const before = this.effectiveWidth();\n this.containerWidth.set(this.host.nativeElement.clientWidth);\n if (this.effectiveWidth() !== before && this.status() === 'ready') this.scheduleDraw();\n });\n }\n\n private cancelRenders(): void {\n for (const t of this.renderTasks) { try { t.cancel?.(); } catch { /* already finished */ } }\n this.renderTasks = [];\n }\n\n private teardown(): void {\n this.cancelRenders();\n const task = this.loadingTask;\n this.loadingTask = null;\n if (task) { try { Promise.resolve(task.destroy?.()).catch(() => undefined); } catch { /* ignore */ } }\n const doc = this.doc;\n this.doc = null;\n this.pageProxies = [];\n if (doc) this.destroyDoc(doc);\n }\n\n private destroyDoc(doc: PDFDocumentProxy): void {\n try { Promise.resolve(doc.destroy()).catch(() => undefined); } catch { /* ignore */ }\n }\n}\n"],"mappings":"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"}
|