geometryview 0.1.1 → 0.3.0
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 +3 -1
- package/package.json +1 -1
- package/src/mcp.mjs +1 -1
- package/src/native.mjs +147 -15
- package/src/page.mjs +6 -1
- package/src/tools.mjs +135 -5
- package/web/build/geometryview-thumbs-web.mjs +2 -0
- package/web/build/geometryview-thumbs-web.wasm +0 -0
- package/web/build/geometryview-web.mjs +1 -1
- package/web/build/geometryview-web.wasm +0 -0
- package/web/chrome.js +7 -3
- package/web/engine.js +9 -0
- package/web/gallery-core.js +359 -0
- package/web/gallery-library.js +262 -0
- package/web/gallery-toolbar.js +148 -0
- package/web/gallery-view.js +1018 -0
- package/web/gallery.css +94 -0
- package/web/gallery.js +563 -0
- package/web/icons.js +6 -0
- package/web/import-queue.js +168 -0
- package/web/import-worker.js +63 -9
- package/web/importers.js +140 -0
- package/web/index.html +1 -0
- package/web/kept.js +263 -0
- package/web/library-store.js +116 -3
- package/web/library.js +25 -1
- package/web/occt/geometryview-step-web.wasm +0 -0
- package/web/occt-threads/geometryview-step-web.wasm +0 -0
- package/web/pdf.js +54 -0
- package/web/structure.js +2 -1
- package/web/thumbs-worker.js +86 -0
- package/web/thumbs.js +97 -0
- package/web/viewer.css +4 -0
- package/web/viewer.js +746 -27
package/web/thumbs.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Draws the gallery's pictures in a worker of their own (thumbs-worker.js), with a GPU device of
|
|
2
|
+
// its own, one at a time. WebAssembly memory never shrinks, so once the worker's heap passes
|
|
3
|
+
// kRecycleMB after a picture it is replaced, as the import worker replaces its OCCT workers; and
|
|
4
|
+
// after a moment with nothing to draw it lets go of the last file it drew.
|
|
5
|
+
|
|
6
|
+
export const kRecycleMB = 256;
|
|
7
|
+
const kTrimAfterMs = 2000;
|
|
8
|
+
|
|
9
|
+
export class Thumbnailer {
|
|
10
|
+
#url;
|
|
11
|
+
#recycleMB;
|
|
12
|
+
#worker = null;
|
|
13
|
+
#ready = null;
|
|
14
|
+
#answers = new Map(); // id -> resolve
|
|
15
|
+
#next = 1;
|
|
16
|
+
#queue = Promise.resolve();
|
|
17
|
+
#trimTimer = 0;
|
|
18
|
+
/** Workers replaced as their memory grew, and the heap of the last picture, for checks. */
|
|
19
|
+
recycled = 0;
|
|
20
|
+
heapMB = 0;
|
|
21
|
+
|
|
22
|
+
constructor({ url = new URL("./thumbs-worker.js", import.meta.url), recycleMB = kRecycleMB } = {}) {
|
|
23
|
+
this.#url = url;
|
|
24
|
+
this.#recycleMB = recycleMB;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Draws a cache file (a Blob or ArrayBuffer) as spec says: { pixels, style, colorMode,
|
|
29
|
+
* pixelsPerPoint, lineScale }, its parts starting at firstColor (-1 for the cycle's own), or a
|
|
30
|
+
* file of one part at folderColor. With keep { key, picture }, the picture and the file's facts
|
|
31
|
+
* are kept (kept.js). Resolves to { bitmap, png, width, height, worldPerPixel, partRect, inkRect,
|
|
32
|
+
* facts, firstColor }; rejects with why it could not be drawn.
|
|
33
|
+
*/
|
|
34
|
+
draw(blob, spec, firstColor = -1, { folderColor = -1, keep = null } = {}) {
|
|
35
|
+
const drawn = this.#queue.then(() => this.#draw(blob, spec, firstColor, folderColor, keep));
|
|
36
|
+
this.#queue = drawn.catch(() => {});
|
|
37
|
+
return drawn;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Ends the worker; a later draw starts another. */
|
|
41
|
+
close() {
|
|
42
|
+
clearTimeout(this.#trimTimer);
|
|
43
|
+
this.#worker?.terminate();
|
|
44
|
+
this.#worker = null;
|
|
45
|
+
this.#ready = null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async #draw(blob, spec, firstColor, folderColor, keep) {
|
|
49
|
+
clearTimeout(this.#trimTimer);
|
|
50
|
+
await this.#start();
|
|
51
|
+
const id = this.#next++;
|
|
52
|
+
const answer = await new Promise((resolve) => {
|
|
53
|
+
this.#answers.set(id, resolve);
|
|
54
|
+
this.#worker.postMessage({ type: "draw", id, blob, pixels: spec.pixels, style: spec.style,
|
|
55
|
+
colorMode: spec.colorMode, pixelsPerPoint: spec.pixelsPerPoint,
|
|
56
|
+
lineScale: spec.lineScale, firstColor, folderColor, keep,
|
|
57
|
+
turn: spec.turn ?? 0, worldPerPixel: spec.worldPerPixel ?? 0,
|
|
58
|
+
supersample: spec.supersample ?? 1 });
|
|
59
|
+
});
|
|
60
|
+
this.heapMB = answer.heapMB ?? this.heapMB;
|
|
61
|
+
if (this.heapMB > this.#recycleMB) {
|
|
62
|
+
this.close();
|
|
63
|
+
this.recycled++;
|
|
64
|
+
} else {
|
|
65
|
+
this.#trimTimer = setTimeout(() => this.#worker?.postMessage({ type: "trim" }), kTrimAfterMs);
|
|
66
|
+
}
|
|
67
|
+
if (!answer.bitmap) throw new Error(answer.message);
|
|
68
|
+
const { bitmap, png, width, height, worldPerPixel, partRect, inkRect, facts } = answer;
|
|
69
|
+
return { bitmap, png, width, height, worldPerPixel, partRect, inkRect, facts, firstColor: answer.firstColor };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#start() {
|
|
73
|
+
if (this.#ready) return this.#ready;
|
|
74
|
+
const worker = new Worker(this.#url, { type: "module" });
|
|
75
|
+
this.#worker = worker;
|
|
76
|
+
this.#ready = new Promise((resolve, reject) => {
|
|
77
|
+
worker.onmessage = ({ data }) => {
|
|
78
|
+
if (data.type === "ready") resolve();
|
|
79
|
+
else if (data.type === "failed") reject(new Error(data.message));
|
|
80
|
+
else if (data.type === "drawn") {
|
|
81
|
+
const answer = this.#answers.get(data.id);
|
|
82
|
+
this.#answers.delete(data.id);
|
|
83
|
+
answer?.(data);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
worker.onerror = (event) => {
|
|
87
|
+
reject(new Error(event.message ?? "The picture worker failed to start."));
|
|
88
|
+
// A draw waiting on a worker that died is answered, so the queue moves on.
|
|
89
|
+
for (const [id, answer] of this.#answers) answer({ id, message: "The picture worker stopped." });
|
|
90
|
+
this.#answers.clear();
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
// A worker that cannot start is not tried again for every picture.
|
|
94
|
+
this.#ready.catch(() => {});
|
|
95
|
+
return this.#ready;
|
|
96
|
+
}
|
|
97
|
+
}
|
package/web/viewer.css
CHANGED
|
@@ -222,6 +222,10 @@ kbd.cap {
|
|
|
222
222
|
pointer-events: none;
|
|
223
223
|
}
|
|
224
224
|
.masthead .title, .masthead .subtitle { text-shadow: 0 0 3px var(--paper); }
|
|
225
|
+
/* The masthead lets clicks through to the view, but for its close button. */
|
|
226
|
+
.masthead .title-row { display: flex; align-items: center; gap: 4px; }
|
|
227
|
+
.masthead .title-row .pill { pointer-events: auto; flex: none; }
|
|
228
|
+
.masthead .title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
225
229
|
.masthead .title { font-size: var(--text-l); font-weight: 600; }
|
|
226
230
|
.masthead .subtitle { margin-top: 2px; font-size: var(--text-s); color: var(--muted); }
|
|
227
231
|
.masthead .progress {
|