postext-folio 0.6.0 → 0.7.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 +8 -4
- package/dist/bookGeometry.d.ts +1 -1
- package/dist/bookGeometry.d.ts.map +1 -1
- package/dist/bookGeometry.js +5 -0
- package/dist/bookGeometry.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/pageFlip.d.ts +31 -19
- package/dist/pageFlip.d.ts.map +1 -1
- package/dist/pageFlip.js +254 -120
- package/dist/pageFlip.js.map +1 -1
- package/dist/paper.d.ts +8 -1
- package/dist/paper.d.ts.map +1 -1
- package/dist/paper.js +21 -4
- package/dist/paper.js.map +1 -1
- package/dist/postext.d.ts +16 -7
- package/dist/postext.d.ts.map +1 -1
- package/dist/postext.js +172 -84
- package/dist/postext.js.map +1 -1
- package/dist/styles.d.ts +1 -1
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +4 -1
- package/dist/styles.js.map +1 -1
- package/dist/videoAtlas.d.ts +90 -0
- package/dist/videoAtlas.d.ts.map +1 -0
- package/dist/videoAtlas.js +241 -0
- package/dist/videoAtlas.js.map +1 -0
- package/dist/videos.d.ts +46 -0
- package/dist/videos.d.ts.map +1 -1
- package/dist/videos.js +55 -1
- package/dist/videos.js.map +1 -1
- package/dist/viewer.d.ts +7 -1
- package/dist/viewer.d.ts.map +1 -1
- package/dist/viewer.js +53 -40
- package/dist/viewer.js.map +1 -1
- package/package.json +3 -3
package/dist/paper.d.ts
CHANGED
|
@@ -37,8 +37,15 @@ export interface PaperSpec {
|
|
|
37
37
|
* through about twice the light its opacity loses (opacity is a contrast
|
|
38
38
|
* over a black backing; diffuse transmittance runs 15–20 % for 80 g/m²
|
|
39
39
|
* offset, a third and more for bible paper).
|
|
40
|
+
*
|
|
41
|
+
* That bending length is the stock's, in millimetres, so across a sheet
|
|
42
|
+
* wider than a book's page (`pageWidthMm`: a tabloid, a Berliner, a
|
|
43
|
+
* broadsheet) it is a smaller share of the page: such a sheet rolls
|
|
44
|
+
* tighter for its width, flutters more and swings back more slowly, as a
|
|
45
|
+
* longer pendulum does. A broadsheet of newsprint flops where a book page
|
|
46
|
+
* of the same paper curls.
|
|
40
47
|
*/
|
|
41
|
-
export declare function paperSpec(paper: ResolvedPaper): PaperSpec;
|
|
48
|
+
export declare function paperSpec(paper: ResolvedPaper, pageWidthMm?: number): PaperSpec;
|
|
42
49
|
/** The paper of a page: the book's, with the page's own stock over it (a
|
|
43
50
|
* page that names a stock takes that stock's defaults, not the book's). */
|
|
44
51
|
export declare function pagePaper(book: FolioConfig | undefined, own: FolioPaperConfig | undefined): ResolvedPaper;
|
package/dist/paper.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paper.d.ts","sourceRoot":"","sources":["../src/paper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEhH,MAAM,MAAM,aAAa,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAEzD,8DAA8D;AAC9D,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,aAAa,CAAC;IACrB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB;6EACyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"paper.d.ts","sourceRoot":"","sources":["../src/paper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEhH,MAAM,MAAM,aAAa,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAEzD,8DAA8D;AAC9D,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,aAAa,CAAC;IACrB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB;6EACyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;CACf;AAkCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAqB/E;AAED;4EAC4E;AAC5E,wBAAgB,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,EAAE,GAAG,EAAE,gBAAgB,GAAG,SAAS,GAAG,aAAa,CAIzG;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAM9D"}
|
package/dist/paper.js
CHANGED
|
@@ -12,8 +12,17 @@ const OPACITY_K = {
|
|
|
12
12
|
cardStock: 0.03,
|
|
13
13
|
board: 0.03,
|
|
14
14
|
};
|
|
15
|
+
/** How much more of the reverse's print shows than the sheet's opacity
|
|
16
|
+
* alone lets through: on newsprint the coldset ink is not dried on the
|
|
17
|
+
* surface but soaks into the open groundwood sheet (strike-through), so
|
|
18
|
+
* the other side reads through more than its 90 % opacity suggests. */
|
|
19
|
+
const STRIKE_THROUGH = {
|
|
20
|
+
newsprint: 1.7,
|
|
21
|
+
};
|
|
15
22
|
/** The reference leaf: 90 g/m² × 1.25 cm³/g. */
|
|
16
23
|
const REF_CALIPER_UM = 112.5;
|
|
24
|
+
/** Pages up to this wide (mm) curl as their stock alone says. */
|
|
25
|
+
const LARGE_PAGE_MM = 230;
|
|
17
26
|
const smooth = (a, b, x) => {
|
|
18
27
|
const t = Math.min(1, Math.max(0, (x - a) / (b - a)));
|
|
19
28
|
return t * t * (3 - 2 * t);
|
|
@@ -28,22 +37,30 @@ const smooth = (a, b, x) => {
|
|
|
28
37
|
* through about twice the light its opacity loses (opacity is a contrast
|
|
29
38
|
* over a black backing; diffuse transmittance runs 15–20 % for 80 g/m²
|
|
30
39
|
* offset, a third and more for bible paper).
|
|
40
|
+
*
|
|
41
|
+
* That bending length is the stock's, in millimetres, so across a sheet
|
|
42
|
+
* wider than a book's page (`pageWidthMm`: a tabloid, a Berliner, a
|
|
43
|
+
* broadsheet) it is a smaller share of the page: such a sheet rolls
|
|
44
|
+
* tighter for its width, flutters more and swings back more slowly, as a
|
|
45
|
+
* longer pendulum does. A broadsheet of newsprint flops where a book page
|
|
46
|
+
* of the same paper curls.
|
|
31
47
|
*/
|
|
32
|
-
export function paperSpec(paper) {
|
|
48
|
+
export function paperSpec(paper, pageWidthMm) {
|
|
33
49
|
const caliperUm = paper.grammage * paper.bulk;
|
|
34
50
|
const ratio = Math.pow(caliperUm / REF_CALIPER_UM, 2 / 3);
|
|
51
|
+
const size = pageWidthMm && pageWidthMm > LARGE_PAGE_MM ? LARGE_PAGE_MM / pageWidthMm : 1;
|
|
35
52
|
const opacity = 1 - Math.exp(-OPACITY_K[paper.type] * paper.grammage);
|
|
36
53
|
const finish = paper.finish;
|
|
37
54
|
return {
|
|
38
55
|
paper,
|
|
39
56
|
caliperMm: caliperUm / 1000,
|
|
40
|
-
roll: Math.min(6, Math.max(0.45, ratio)),
|
|
57
|
+
roll: Math.min(6, Math.max(0.45, ratio)) * size,
|
|
41
58
|
rigidity: smooth(1.3, 4, ratio),
|
|
42
59
|
opacity,
|
|
43
|
-
showThrough: paper.showThrough ? Math.min(0.4, (1 - opacity) * 1.25) : 0,
|
|
60
|
+
showThrough: paper.showThrough ? Math.min(0.4, (1 - opacity) * 1.25 * (STRIKE_THROUGH[paper.type] ?? 1)) : 0,
|
|
44
61
|
transmission: paper.showThrough ? Math.min(0.5, (1 - opacity) * 2) : 0,
|
|
45
62
|
follow: 0.35 / (1 + 0.35 * Math.max(0, Math.log(ratio))),
|
|
46
|
-
spring: 0.0085 * Math.min(1.6, Math.max(0.75, Math.sqrt(ratio))),
|
|
63
|
+
spring: 0.0085 * Math.min(1.6, Math.max(0.75, Math.sqrt(ratio))) * Math.sqrt(size),
|
|
47
64
|
roughness: finish === "gloss" ? 0.32 : finish === "silk" ? 0.5 : finish === "matte" ? 0.7 : 0.88,
|
|
48
65
|
clearcoat: finish === "gloss" ? 1 : finish === "silk" ? 0.45 : finish === "matte" ? 0.12 : 0,
|
|
49
66
|
clearcoatRoughness: finish === "gloss" ? 0.06 : finish === "silk" ? 0.28 : 0.6,
|
package/dist/paper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paper.js","sourceRoot":"","sources":["../src/paper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAqE,MAAM,SAAS,CAAC;AAgChH;4EAC4E;AAC5E,MAAM,SAAS,GAA0C;IACvD,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,KAAK;IACf,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,KAAK;IACjB,WAAW,EAAE,KAAK;IAClB,KAAK,EAAE,KAAK;IACZ,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,IAAI;IACf,KAAK,EAAE,IAAI;CACZ,CAAC;AAEF,gDAAgD;AAChD,MAAM,cAAc,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"paper.js","sourceRoot":"","sources":["../src/paper.ts"],"names":[],"mappings":"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"}
|
package/dist/postext.d.ts
CHANGED
|
@@ -22,11 +22,17 @@ export interface FolioDocumentOptions extends Omit<FolioOptions, "pages" | "firs
|
|
|
22
22
|
/**
|
|
23
23
|
* Videos printed on the pages play there (#477): a click on a video's
|
|
24
24
|
* poster plays it on the page (in every pointer mode), a click on it
|
|
25
|
-
* again pauses it, and it goes on playing while its leaf turns.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
25
|
+
* again pauses it, and it goes on playing while its leaf turns. Several
|
|
26
|
+
* may play at once (#507, up to eight drawn): starting a video stops the
|
|
27
|
+
* other exclusive ones (`player.exclusive`, the default) and holds those
|
|
28
|
+
* playing alongside (`exclusive: false`) until it pauses or ends; one
|
|
29
|
+
* playing alongside pauses only the exclusive ones. A video with
|
|
30
|
+
* `player.autoplay` starts by itself, muted: an exclusive one the first
|
|
31
|
+
* time its spread is shown (with its sound once the reader has
|
|
32
|
+
* interacted with the page), one playing alongside each time its page
|
|
33
|
+
* comes into view, unless the reader asks for less motion
|
|
34
|
+
* (`prefers-reduced-motion`). A video stops when the book comes to rest
|
|
35
|
+
* on a spread that does not show it. Self-hosted videos only (a file, or its
|
|
30
36
|
* address: MP4, WebM or an HLS stream); a YouTube or Vimeo poster turns
|
|
31
37
|
* the page as any other. The video's server must allow cross-origin
|
|
32
38
|
* reads (CORS) for WebGL to draw it. Default true.
|
|
@@ -61,7 +67,7 @@ export interface FolioDocumentViewer extends FolioViewer {
|
|
|
61
67
|
/** Plays or pauses the video printed at a point of a page, as a click
|
|
62
68
|
* there does; false when no playable video lies there. */
|
|
63
69
|
toggleVideoAt(point: FolioPagePoint): boolean;
|
|
64
|
-
/** Stops the
|
|
70
|
+
/** Stops the videos playing on the pages (their posters show again). */
|
|
65
71
|
stopVideo(): void;
|
|
66
72
|
}
|
|
67
73
|
/** Whether the document's first page is a recto: page 1, or a chapter
|
|
@@ -79,7 +85,10 @@ export declare function trimmedSize(page: VDTPage, doc: VDTDocument): {
|
|
|
79
85
|
* book), with the host's own appearance laid over them. The pages round
|
|
80
86
|
* it are the host's word when it gives them (`extraPages`: a host laying
|
|
81
87
|
* a book out a chapter at a time knows the chapters after this one, which
|
|
82
|
-
* the document only knows when it was given the book's page count).
|
|
88
|
+
* the document only knows when it was given the book's page count). A
|
|
89
|
+
* newspaper trim (`page.sizePreset` broadsheet, berliner, tabloid or
|
|
90
|
+
* compact) shows folded newsprint unless the settings name a stock or a
|
|
91
|
+
* binding (#506). */
|
|
83
92
|
export declare function appearanceOf(doc: VDTDocument, own: FolioAppearance | undefined): FolioAppearance;
|
|
84
93
|
/**
|
|
85
94
|
* Which paintings a new layout can keep: new page index → old page index,
|
package/dist/postext.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postext.d.ts","sourceRoot":"","sources":["../src/postext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,WAAW,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAG7E,OAAO,EAAe,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAuC,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5J,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,GAAG,IAAI,GAAG,QAAQ,CAAC;IACxH,gDAAgD;IAChD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;qBAEiB;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mDAAmD;IACnD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,wBAAwB,KAAK,OAAO,CAAC;IACrE
|
|
1
|
+
{"version":3,"file":"postext.d.ts","sourceRoot":"","sources":["../src/postext.ts"],"names":[],"mappings":"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"}
|
package/dist/postext.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { renderPageToCanvas } from "postext";
|
|
2
|
-
import { resolveFolioConfig } from "postext";
|
|
2
|
+
import { folioForTrim, resolveFolioConfig } from "postext";
|
|
3
3
|
import { BLOCK_PAGES } from "./pageFlip";
|
|
4
4
|
import { createFolio } from "./viewer";
|
|
5
|
-
import { attachVideoSource, isHlsVideo, pageVideoSpots, spotContains } from "./videos";
|
|
5
|
+
import { attachVideoSource, autoKey, autoplayPlan, isHlsVideo, makeWay, pageVideoSpots, spotContains } from "./videos";
|
|
6
6
|
/** Whether the document's first page is a recto: page 1, or a chapter
|
|
7
7
|
* continued after an even number of pages. */
|
|
8
8
|
export function firstPageIsRecto(doc) {
|
|
@@ -25,12 +25,15 @@ function paperOf(doc) {
|
|
|
25
25
|
* book), with the host's own appearance laid over them. The pages round
|
|
26
26
|
* it are the host's word when it gives them (`extraPages`: a host laying
|
|
27
27
|
* a book out a chapter at a time knows the chapters after this one, which
|
|
28
|
-
* the document only knows when it was given the book's page count).
|
|
28
|
+
* the document only knows when it was given the book's page count). A
|
|
29
|
+
* newspaper trim (`page.sizePreset` broadsheet, berliner, tabloid or
|
|
30
|
+
* compact) shows folded newsprint unless the settings name a stock or a
|
|
31
|
+
* binding (#506). */
|
|
29
32
|
export function appearanceOf(doc, own) {
|
|
30
33
|
const page = doc.pages[0];
|
|
31
34
|
const before = Math.max(0, own?.extraPages?.before ?? doc.pageIndexOffset ?? 0);
|
|
32
35
|
const after = Math.max(0, own?.extraPages?.after ?? (doc.bookPageCount ?? 0) - before - doc.pages.length);
|
|
33
|
-
const folio = own && "folio" in own ? own.folio : doc.config.folio;
|
|
36
|
+
const folio = folioForTrim(own && "folio" in own ? own.folio : doc.config.folio, doc.config.page.sizePreset);
|
|
34
37
|
// The document's own covers: the book's first page (a recto) and its
|
|
35
38
|
// last, when that is a verso (an even page number). A chapter from the
|
|
36
39
|
// middle of the book has neither: its first and last leaves are paper
|
|
@@ -38,11 +41,11 @@ export function appearanceOf(doc, own) {
|
|
|
38
41
|
const ownCovers = resolveFolioConfig(folio).binding.cover === "pages";
|
|
39
42
|
const total = before + doc.pages.length;
|
|
40
43
|
return {
|
|
41
|
-
folio: doc.config.folio,
|
|
42
44
|
covers: { front: ownCovers && before === 0, back: ownCovers && after === 0 && total % 2 === 0 },
|
|
43
45
|
// Page sizes are in device pixels at the page's dpi.
|
|
44
46
|
...(page ? { pageWidthMm: (trimmedSize(page, doc).width * 25.4) / (doc.config.page.dpi || 300) } : {}),
|
|
45
47
|
...own,
|
|
48
|
+
folio,
|
|
46
49
|
extraPages: { before, after },
|
|
47
50
|
};
|
|
48
51
|
}
|
|
@@ -124,6 +127,9 @@ export function sweepFor(run, settled, target, count) {
|
|
|
124
127
|
}
|
|
125
128
|
/** Painting time per frame while leaves are in the air. */
|
|
126
129
|
const SWEEP_BUDGET_MS = 8;
|
|
130
|
+
/** The reader has asked for less motion: no video starts on its own to
|
|
131
|
+
* play alongside the others. */
|
|
132
|
+
const reducedMotion = () => typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
127
133
|
/** How long the book must stay as it is before a video set to play on its
|
|
128
134
|
* own starts (a host's layouts settling, a run of turns). */
|
|
129
135
|
const AUTOPLAY_SETTLE_MS = 700;
|
|
@@ -326,14 +332,18 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
326
332
|
// The leaf a hand would lift next shows the neighbours' pages.
|
|
327
333
|
return [...pages, pages[0] - 2, pages[0] - 1, pages[pages.length - 1] + 1, pages[pages.length - 1] + 2];
|
|
328
334
|
};
|
|
329
|
-
// ── Videos on the pages (#477) ──
|
|
335
|
+
// ── Videos on the pages (#477, #507) ──
|
|
330
336
|
/** The video spots of each page of the current document, as found. */
|
|
331
337
|
let spots = new Map();
|
|
332
|
-
/** The
|
|
333
|
-
*
|
|
334
|
-
let
|
|
335
|
-
/** The videos that have started on their own once (`player.autoplay`
|
|
338
|
+
/** The videos playing (or paused) on the pages, in the order they
|
|
339
|
+
* started. */
|
|
340
|
+
let players = [];
|
|
341
|
+
/** The videos that have started on their own once (`player.autoplay`
|
|
342
|
+
* with `exclusive`). */
|
|
336
343
|
const autoplayed = new Set();
|
|
344
|
+
/** The videos playing alongside that have started on their own since
|
|
345
|
+
* their page last came into view (`page|key`). */
|
|
346
|
+
const autoStarted = new Set();
|
|
337
347
|
const spotsOf = (i) => {
|
|
338
348
|
let found = spots.get(i);
|
|
339
349
|
if (!found) {
|
|
@@ -351,57 +361,118 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
351
361
|
return (v.fileId ? options.videoUrl?.(v.fileId) : undefined) ?? v.link;
|
|
352
362
|
};
|
|
353
363
|
const spotAt = (point) => options.videos === false ? undefined : spotsOf(point.page).find((s) => urlOf(s) && spotContains(s, point.x, point.y));
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
364
|
+
const playerOf = (page, spot) => players.find((p) => p.page === page && p.spot.key === spot.key);
|
|
365
|
+
const onShow = (p) => viewer.state.pages.includes(p.page);
|
|
366
|
+
const report = (p, state) => {
|
|
367
|
+
options.onVideo?.({ resourceId: p.spot.resourceId, page: p.page, state });
|
|
357
368
|
};
|
|
358
|
-
/** Shows the
|
|
359
|
-
function
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
viewer.setPageVideo({ page: playing.page, element: playing.element, origin: playing.spot.origin, across: playing.spot.across, down: playing.spot.down, ...(playing.spot.crop ? { crop: playing.spot.crop } : {}) });
|
|
369
|
+
/** Shows the videos that have a frame to show on their pages. */
|
|
370
|
+
function showVideos() {
|
|
371
|
+
viewer.setPageVideos(players
|
|
372
|
+
.filter((p) => p.shown)
|
|
373
|
+
.map((p) => ({ page: p.page, element: p.element, origin: p.spot.origin, across: p.spot.across, down: p.spot.down, ...(p.spot.crop ? { crop: p.spot.crop } : {}) })));
|
|
364
374
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
if (!p)
|
|
375
|
+
/** Stops a video: its poster shows again, and the videos it held go on. */
|
|
376
|
+
function stopPlayer(p, state = "stopped") {
|
|
377
|
+
if (!players.includes(p))
|
|
368
378
|
return;
|
|
369
|
-
|
|
370
|
-
|
|
379
|
+
players = players.filter((q) => q !== p);
|
|
380
|
+
report(p, state);
|
|
371
381
|
p.element.pause();
|
|
372
382
|
p.release?.();
|
|
373
383
|
if (p.shown)
|
|
374
|
-
|
|
384
|
+
showVideos();
|
|
385
|
+
resumeHeld(p);
|
|
386
|
+
}
|
|
387
|
+
function stopVideos() {
|
|
388
|
+
for (const p of [...players])
|
|
389
|
+
stopPlayer(p);
|
|
390
|
+
}
|
|
391
|
+
/** The videos playing alongside that `by` held go on (on show only),
|
|
392
|
+
* and those set to play on their own that have not started yet start. */
|
|
393
|
+
function resumeHeld(by) {
|
|
394
|
+
if (by.alongside)
|
|
395
|
+
return;
|
|
396
|
+
for (const q of players) {
|
|
397
|
+
if (q.heldBy !== by)
|
|
398
|
+
continue;
|
|
399
|
+
q.heldBy = null;
|
|
400
|
+
if (onShow(q))
|
|
401
|
+
void q.element.play().catch(() => { });
|
|
402
|
+
}
|
|
403
|
+
if (!turning)
|
|
404
|
+
autoplayOn(viewer.state.pages, { exclusive: false });
|
|
405
|
+
}
|
|
406
|
+
/** A video starts (or goes on): the others make way for it (see
|
|
407
|
+
* `makeWay`). */
|
|
408
|
+
function makeWayFor(p) {
|
|
409
|
+
p.heldBy = null;
|
|
410
|
+
// Those waiting for another exclusive video wait for this one now.
|
|
411
|
+
if (!p.alongside)
|
|
412
|
+
for (const q of players)
|
|
413
|
+
if (q.heldBy)
|
|
414
|
+
q.heldBy = p;
|
|
415
|
+
const list = [...players.filter((q) => q !== p), p].map((q) => ({ q, alongside: q.alongside, paused: q.element.paused }));
|
|
416
|
+
const way = makeWay(list[list.length - 1], list);
|
|
417
|
+
for (const { q } of way.hold) {
|
|
418
|
+
q.heldBy = p;
|
|
419
|
+
q.element.pause();
|
|
420
|
+
}
|
|
421
|
+
for (const { q } of way.pause)
|
|
422
|
+
q.element.pause();
|
|
423
|
+
for (const { q } of way.stop)
|
|
424
|
+
stopPlayer(q);
|
|
375
425
|
}
|
|
426
|
+
/** Plays the video at `spot` on `page`, from its start; `auto` when it
|
|
427
|
+
* starts on its own. */
|
|
376
428
|
function startVideo(page, spot, auto = false) {
|
|
377
|
-
stopVideo();
|
|
378
429
|
const url = urlOf(spot);
|
|
379
430
|
if (!url)
|
|
380
431
|
return;
|
|
432
|
+
const player = spot.video.player;
|
|
433
|
+
const alongside = player.exclusive === false;
|
|
381
434
|
const element = document.createElement("video");
|
|
382
435
|
element.playsInline = true;
|
|
383
436
|
element.preload = "auto";
|
|
384
437
|
// WebGL draws the picture only when its server allows the read.
|
|
385
438
|
if (!/^(blob|data):/i.test(url))
|
|
386
439
|
element.crossOrigin = "anonymous";
|
|
387
|
-
const
|
|
440
|
+
const range = { start: spot.video.start ?? 0, end: spot.video.end };
|
|
441
|
+
// A loop from the file's start loops by itself (seamlessly); one from
|
|
442
|
+
// later on is sent back by hand.
|
|
443
|
+
element.loop = player.loop && !range.start;
|
|
388
444
|
// A video that starts on its own has its sound once the reader has
|
|
389
445
|
// clicked or typed on the page (the browser allows it then); before
|
|
390
446
|
// that it starts muted, as browsers require, and a click unmutes it.
|
|
447
|
+
// One playing alongside always starts muted on its own: a page of
|
|
448
|
+
// living pictures is a quiet one.
|
|
391
449
|
const activated = navigator.userActivation?.hasBeenActive ?? false;
|
|
392
|
-
element.muted = player.muted || (auto && !activated);
|
|
393
|
-
const entry = { page, spot, element, shown: false, autoMuted: !player.muted && element.muted };
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
450
|
+
element.muted = player.muted || (auto && (alongside || !activated));
|
|
451
|
+
const entry = { page, spot, element, shown: false, autoMuted: !player.muted && element.muted, alongside, heldBy: null };
|
|
452
|
+
// The others make way at once (an exclusive one, still loading, holds
|
|
453
|
+
// the videos playing alongside from now).
|
|
454
|
+
players = [...players, entry];
|
|
455
|
+
makeWayFor(entry);
|
|
456
|
+
const live = () => players.includes(entry);
|
|
457
|
+
element.addEventListener("error", () => live() && stopPlayer(entry, "error"));
|
|
398
458
|
element.addEventListener("loadedmetadata", () => {
|
|
399
459
|
if (range.start)
|
|
400
460
|
element.currentTime = range.start;
|
|
401
461
|
}, { once: true });
|
|
402
|
-
element.addEventListener("loadeddata", () =>
|
|
403
|
-
|
|
404
|
-
|
|
462
|
+
element.addEventListener("loadeddata", () => {
|
|
463
|
+
if (!live())
|
|
464
|
+
return;
|
|
465
|
+
entry.shown = true;
|
|
466
|
+
showVideos();
|
|
467
|
+
}, { once: true });
|
|
468
|
+
element.addEventListener("play", () => live() && makeWayFor(entry));
|
|
469
|
+
element.addEventListener("playing", () => live() && report(entry, "playing"));
|
|
470
|
+
element.addEventListener("pause", () => {
|
|
471
|
+
if (!live() || element.ended)
|
|
472
|
+
return;
|
|
473
|
+
report(entry, "paused");
|
|
474
|
+
resumeHeld(entry);
|
|
475
|
+
});
|
|
405
476
|
const atEnd = () => {
|
|
406
477
|
if (!live())
|
|
407
478
|
return;
|
|
@@ -410,7 +481,7 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
410
481
|
void element.play().catch(() => { });
|
|
411
482
|
}
|
|
412
483
|
else
|
|
413
|
-
|
|
484
|
+
stopPlayer(entry);
|
|
414
485
|
};
|
|
415
486
|
element.addEventListener("ended", atEnd);
|
|
416
487
|
element.addEventListener("timeupdate", () => {
|
|
@@ -424,6 +495,9 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
424
495
|
if (!live())
|
|
425
496
|
return release();
|
|
426
497
|
entry.release = release;
|
|
498
|
+
// Held back already (an exclusive video started meanwhile).
|
|
499
|
+
if (entry.heldBy)
|
|
500
|
+
return;
|
|
427
501
|
// The click's gesture lets it play with sound; a browser that still
|
|
428
502
|
// refuses gets it muted.
|
|
429
503
|
element.play().catch((err) => {
|
|
@@ -435,8 +509,8 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
435
509
|
return element.play();
|
|
436
510
|
}
|
|
437
511
|
throw err;
|
|
438
|
-
}).catch(() => live() &&
|
|
439
|
-
}, () => live() &&
|
|
512
|
+
}).catch(() => live() && stopPlayer(entry, "error"));
|
|
513
|
+
}, () => live() && stopPlayer(entry, "error"));
|
|
440
514
|
}
|
|
441
515
|
/** A click at a point of a page: plays, pauses or resumes the video
|
|
442
516
|
* printed there. */
|
|
@@ -444,18 +518,16 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
444
518
|
const spot = spotAt(point);
|
|
445
519
|
if (!spot)
|
|
446
520
|
return false;
|
|
447
|
-
|
|
448
|
-
|
|
521
|
+
const p = playerOf(point.page, spot);
|
|
522
|
+
if (p)
|
|
523
|
+
togglePlaying(p);
|
|
449
524
|
else
|
|
450
525
|
startVideo(point.page, spot);
|
|
451
526
|
return true;
|
|
452
527
|
}
|
|
453
|
-
/** A click (or Space) on
|
|
528
|
+
/** A click (or Space) on a video playing: one that started on its own
|
|
454
529
|
* is unmuted first; otherwise it pauses or resumes. */
|
|
455
|
-
function togglePlaying() {
|
|
456
|
-
const p = playing;
|
|
457
|
-
if (!p)
|
|
458
|
-
return;
|
|
530
|
+
function togglePlaying(p) {
|
|
459
531
|
if (p.autoMuted && !p.element.paused) {
|
|
460
532
|
p.autoMuted = false;
|
|
461
533
|
p.element.muted = false;
|
|
@@ -477,42 +549,51 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
477
549
|
autoplayOn(viewer.state.pages);
|
|
478
550
|
}, AUTOPLAY_SETTLE_MS);
|
|
479
551
|
};
|
|
480
|
-
/**
|
|
481
|
-
*
|
|
482
|
-
|
|
483
|
-
|
|
552
|
+
/**
|
|
553
|
+
* The videos on show set to play on their own (`player.autoplay`) start,
|
|
554
|
+
* muted. One playing alongside the others (`exclusive: false`) starts
|
|
555
|
+
* each time its page comes into view (not while an exclusive video
|
|
556
|
+
* plays there, nor when the reader asks for less motion); an exclusive
|
|
557
|
+
* one, the first time its spread is shown and never again in this
|
|
558
|
+
* viewer, when no other exclusive video is on.
|
|
559
|
+
*/
|
|
560
|
+
function autoplayOn(pages, { exclusive = true } = {}) {
|
|
561
|
+
if (options.videos === false)
|
|
484
562
|
return;
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
563
|
+
const state = {
|
|
564
|
+
players: players.map((p) => ({ page: p.page, key: p.spot.key, alongside: p.alongside, paused: p.element.paused, shown: p.shown })),
|
|
565
|
+
autoplayed,
|
|
566
|
+
autoStarted,
|
|
567
|
+
};
|
|
568
|
+
for (const { page, spot } of autoplayPlan(pages, spotsOf, (s) => !!urlOf(s), state, { exclusive, reducedMotion: reducedMotion() })) {
|
|
569
|
+
if (spot.video.player.exclusive === false)
|
|
570
|
+
autoStarted.add(autoKey(page, spot.key));
|
|
571
|
+
else
|
|
489
572
|
autoplayed.add(spot.key);
|
|
490
|
-
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
573
|
+
startVideo(page, spot, true);
|
|
493
574
|
}
|
|
494
575
|
}
|
|
495
|
-
/** A new layout:
|
|
496
|
-
*
|
|
497
|
-
|
|
576
|
+
/** A new layout: each video follows its resource to where the layout
|
|
577
|
+
* puts it, or stops when it is gone (or, at rest, off the pages on
|
|
578
|
+
* show). */
|
|
579
|
+
function followVideos() {
|
|
498
580
|
spots = new Map();
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
near.
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
if (!spot)
|
|
581
|
+
let moved = false;
|
|
582
|
+
for (const p of [...players]) {
|
|
583
|
+
const near = [p.page, ...viewer.state.pages];
|
|
584
|
+
for (let i = 0; i < current.pages.length; i++)
|
|
585
|
+
near.push(i);
|
|
586
|
+
const at = near.find((i) => spotsOf(i).some((s) => s.key === p.spot.key && urlOf(s) === urlOf(p.spot)));
|
|
587
|
+
if (at === undefined || (!turning && !viewer.state.pages.includes(at))) {
|
|
588
|
+
stopPlayer(p);
|
|
508
589
|
continue;
|
|
509
|
-
|
|
510
|
-
p.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
return;
|
|
590
|
+
}
|
|
591
|
+
p.page = at;
|
|
592
|
+
p.spot = spotsOf(at).find((s) => s.key === p.spot.key && urlOf(s) === urlOf(p.spot));
|
|
593
|
+
moved ||= p.shown;
|
|
514
594
|
}
|
|
515
|
-
|
|
595
|
+
if (moved)
|
|
596
|
+
showVideos();
|
|
516
597
|
}
|
|
517
598
|
const first = doc.pages[0];
|
|
518
599
|
const viewer = createFolio(container, {
|
|
@@ -538,9 +619,13 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
538
619
|
isPageAction: (point) => !!spotAt(point) || !!options.isPageAction?.(point),
|
|
539
620
|
onChange: (state) => {
|
|
540
621
|
// A video whose page has turned away stops; one set to play on its
|
|
541
|
-
// own starts
|
|
542
|
-
|
|
543
|
-
|
|
622
|
+
// own starts when its spread is shown (see `autoplayOn`).
|
|
623
|
+
for (const p of [...players])
|
|
624
|
+
if (!state.pages.includes(p.page))
|
|
625
|
+
stopPlayer(p);
|
|
626
|
+
for (const key of [...autoStarted])
|
|
627
|
+
if (!state.pages.some((i) => key.startsWith(autoKey(i, ""))))
|
|
628
|
+
autoStarted.delete(key);
|
|
544
629
|
scheduleAutoplay();
|
|
545
630
|
focus = state.pages;
|
|
546
631
|
settled = state.pages;
|
|
@@ -570,7 +655,7 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
570
655
|
// Debugging (`__postextFolioPreserve`, as for the renderer): the videos.
|
|
571
656
|
if (globalThis.__postextFolioPreserve) {
|
|
572
657
|
globalThis.__postextFolioVideos = {
|
|
573
|
-
playing: () =>
|
|
658
|
+
playing: () => players,
|
|
574
659
|
autoplayed,
|
|
575
660
|
spots: (i) => spotsOf(i),
|
|
576
661
|
state: () => viewer.state,
|
|
@@ -582,8 +667,10 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
582
667
|
if (event.target !== viewer.element || (event.key !== " " && event.key !== "Enter") || options.videos === false)
|
|
583
668
|
return;
|
|
584
669
|
const on = viewer.state.pages;
|
|
585
|
-
|
|
586
|
-
|
|
670
|
+
const shown = players.filter((p) => on.includes(p.page));
|
|
671
|
+
const p = shown.find((x) => !x.alongside) ?? shown[0];
|
|
672
|
+
if (p)
|
|
673
|
+
togglePlaying(p);
|
|
587
674
|
else {
|
|
588
675
|
const page = on.find((i) => spotsOf(i).some((s) => urlOf(s)));
|
|
589
676
|
if (page === undefined)
|
|
@@ -601,8 +688,9 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
601
688
|
setPages: viewer.setPages,
|
|
602
689
|
refreshPage: viewer.refreshPage,
|
|
603
690
|
setPageVideo: viewer.setPageVideo,
|
|
691
|
+
setPageVideos: viewer.setPageVideos,
|
|
604
692
|
toggleVideoAt,
|
|
605
|
-
stopVideo:
|
|
693
|
+
stopVideo: stopVideos,
|
|
606
694
|
setLabels: viewer.setLabels,
|
|
607
695
|
resetView: viewer.resetView,
|
|
608
696
|
getView: viewer.getView,
|
|
@@ -679,7 +767,7 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
679
767
|
run = null;
|
|
680
768
|
}
|
|
681
769
|
refresh(around(viewer.state));
|
|
682
|
-
|
|
770
|
+
followVideos();
|
|
683
771
|
scheduleAutoplay();
|
|
684
772
|
},
|
|
685
773
|
redecorate(pages) {
|
|
@@ -698,7 +786,7 @@ export function createFolioFromDocument(container, doc, options = {}) {
|
|
|
698
786
|
},
|
|
699
787
|
dispose() {
|
|
700
788
|
clearTimeout(autoTimer);
|
|
701
|
-
|
|
789
|
+
stopVideos();
|
|
702
790
|
cancelIdle(idle);
|
|
703
791
|
cancelAnimationFrame(sweepFrame);
|
|
704
792
|
clearTimeout(resizeTimer);
|