@netless/forge-imagery-doc 0.1.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.
Files changed (46) hide show
  1. package/build.mjs +34 -0
  2. package/dist/Cont.d.ts +1 -0
  3. package/dist/Cont.d.ts.map +1 -0
  4. package/dist/Container.d.ts +16 -0
  5. package/dist/Container.d.ts.map +1 -0
  6. package/dist/ContinuousContainer.d.ts +31 -0
  7. package/dist/ContinuousContainer.d.ts.map +1 -0
  8. package/dist/FooterView.d.ts +18 -0
  9. package/dist/FooterView.d.ts.map +1 -0
  10. package/dist/ImageryDoc.d.ts +57 -0
  11. package/dist/ImageryDoc.d.ts.map +1 -0
  12. package/dist/ImageryDocApplication.d.ts +38 -0
  13. package/dist/ImageryDocApplication.d.ts.map +1 -0
  14. package/dist/ImageryDocPermissions.d.ts +80 -0
  15. package/dist/ImageryDocPermissions.d.ts.map +1 -0
  16. package/dist/InfinityScroll.d.ts +15 -0
  17. package/dist/InfinityScroll.d.ts.map +1 -0
  18. package/dist/LazyImage.d.ts +11 -0
  19. package/dist/LazyImage.d.ts.map +1 -0
  20. package/dist/SideBarView.d.ts +4 -0
  21. package/dist/SideBarView.d.ts.map +1 -0
  22. package/dist/SingleContainer.d.ts +36 -0
  23. package/dist/SingleContainer.d.ts.map +1 -0
  24. package/dist/icons.d.ts +6 -0
  25. package/dist/icons.d.ts.map +1 -0
  26. package/dist/imagery-doc.esm.js +1031 -0
  27. package/dist/imagery-doc.esm.js.map +7 -0
  28. package/dist/imagery-doc.js +1064 -0
  29. package/dist/imagery-doc.js.map +7 -0
  30. package/dist/index.d.ts +5 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/infinityScrollor.d.ts +5 -0
  33. package/dist/infinityScrollor.d.ts.map +1 -0
  34. package/package.json +23 -0
  35. package/src/Container.ts +17 -0
  36. package/src/ContinuousContainer.ts +157 -0
  37. package/src/FooterView.ts +139 -0
  38. package/src/ImageryDoc.ts +64 -0
  39. package/src/ImageryDocApplication.ts +225 -0
  40. package/src/ImageryDocPermissions.ts +159 -0
  41. package/src/InfinityScroll.ts +55 -0
  42. package/src/LazyImage.ts +66 -0
  43. package/src/SingleContainer.ts +248 -0
  44. package/src/icons.ts +9 -0
  45. package/src/index.ts +5 -0
  46. package/tsconfig.json +7 -0
@@ -0,0 +1,248 @@
1
+ import {LazyImage} from "./LazyImage";
2
+ import {InfinityScroll} from "./InfinityScroll";
3
+ import * as Y from "yjs";
4
+ import {WhiteboardApplication} from "@netless/forge-whiteboard";
5
+ import type {ImageryDoc} from "./ImageryDoc";
6
+ import {Container, ContainerKeys} from "./Container";
7
+
8
+ export const delay = (value: number) => new Promise(resolve => setTimeout(resolve, value));
9
+
10
+ async function waitUntil(fn: () => boolean, timeout: number): Promise<void> {
11
+ let start = Date.now();
12
+ while (!fn() && Date.now() - start < timeout) {
13
+ await delay(50);
14
+ start = Date.now();
15
+ }
16
+ }
17
+
18
+ export class SingleContainer implements Container {
19
+ public readonly view: HTMLDivElement;
20
+ private parentView: HTMLDivElement;
21
+ private resizeObserver!: ResizeObserver;
22
+ private images: LazyImage[] = [];
23
+ private currentImage: LazyImage | null = null;
24
+ private scroll: InfinityScroll;
25
+ private map: Y.Map<any>;
26
+ private whiteboardApp: WhiteboardApplication;
27
+ private timeoutId: any = null;
28
+ private imageDoc: ImageryDoc;
29
+
30
+ private get scale(): number {
31
+ return this.map.get(ContainerKeys.scale);
32
+ }
33
+ private set scale(value: number) {
34
+ this.map.set(ContainerKeys.scale, value);
35
+ }
36
+ private get translateX(): number {
37
+ return this.map.get(ContainerKeys.translateX);
38
+ }
39
+ private set translateX(value: number) {
40
+ this.map.set(ContainerKeys.translateX, value);
41
+ }
42
+ private get translateY(): number {
43
+ return this.map.get(ContainerKeys.translateY);
44
+ }
45
+ private set translateY(value: number) {
46
+ this.map.set(ContainerKeys.translateY, value);
47
+ }
48
+ public get pageIndex(): number {
49
+ return this.map.get(ContainerKeys.pageIndex);
50
+ }
51
+
52
+ public constructor(
53
+ map: Y.Map<any>,
54
+ whiteboardApp: WhiteboardApplication,
55
+ parentView: HTMLDivElement,
56
+ imageDoc: ImageryDoc,
57
+ ) {
58
+ this.imageDoc = imageDoc;
59
+ this.parentView = parentView;
60
+ this.map = map;
61
+ this.scroll = new InfinityScroll(this.parentView);
62
+ this.whiteboardApp = whiteboardApp;
63
+ this.view = document.createElement("div");
64
+ this.view.style.width = "100%";
65
+ this.view.style.height = "100%";
66
+ this.view.style.position = "absolute";
67
+ this.view.style.top = "0";
68
+ this.view.style.left = "0";
69
+ this.view.style.transformOrigin = "center";
70
+ this.view.setAttribute("data-imagery-container", "single");
71
+
72
+ this.resizeObserver = new ResizeObserver(this.handleResize);
73
+ this.resizeObserver.observe(this.view);
74
+ (window as any).imageWhiteboard = this.whiteboardApp;
75
+
76
+ this.whiteboardApp.updateInternalResizeObserverStatus(false);
77
+ this.map.observe(this.handleMapChange);
78
+ if (!this.map.has(ContainerKeys.scale)) {
79
+ this.map.set(ContainerKeys.scale, 1);
80
+ }
81
+ if (!this.map.has(ContainerKeys.translateX)) {
82
+ this.map.set(ContainerKeys.translateX, 0);
83
+ }
84
+ if (!this.map.has(ContainerKeys.translateY)) {
85
+ this.map.set(ContainerKeys.translateY, 0);
86
+ }
87
+ if (!this.map.has(ContainerKeys.pageIndex)) {
88
+ this.map.set(ContainerKeys.pageIndex, 0);
89
+ }
90
+ this.scroll.on("translate", (dx, dy) => {
91
+ this.handleTranslate(dx, dy);
92
+ });
93
+ this.scroll.on("scale", (scale) => {
94
+ let nextScale = this.scale * scale;
95
+ nextScale = Math.max(1, nextScale);
96
+ nextScale = Math.min(2, nextScale);
97
+ this.scale = nextScale;
98
+ this.handleTranslate(0, 0);
99
+ });
100
+ }
101
+
102
+ public init() {
103
+ this.handleGoto(this.pageIndex)
104
+ .catch(error => {
105
+ // todo error
106
+ });
107
+ this.updateSyncedTransform();
108
+ }
109
+
110
+ private handleTranslate(dx: number, dy: number) {
111
+ const image = this.view.children[0];
112
+ if (!image) {
113
+ return;
114
+ }
115
+ const imageBounds = image.getBoundingClientRect();
116
+ const parentBounds = this.parentView.getBoundingClientRect();
117
+ const maxDx = (imageBounds.width - parentBounds.width) / 2;
118
+ const maxDy = (imageBounds.height - parentBounds.height) / 2;
119
+
120
+ if (maxDx > 0) {
121
+ let nextDx = this.translateX * parentBounds.width + dx;
122
+ if (nextDx >= 0) {
123
+ nextDx = Math.min(nextDx, maxDx);
124
+ } else {
125
+ nextDx = Math.max(nextDx, -maxDx);
126
+ }
127
+ this.translateX = nextDx / parentBounds.width;
128
+ } else {
129
+ this.translateX = 0;
130
+ }
131
+ if (maxDy > 0) {
132
+ let nextDy = this.translateY * parentBounds.height + dy;
133
+ if (nextDy >= 0) {
134
+ nextDy = Math.min(nextDy, maxDy);
135
+ } else {
136
+ nextDy = Math.max(nextDy, -maxDy);
137
+ }
138
+ this.translateY = nextDy / parentBounds.height;
139
+ } else {
140
+ this.translateY = 0;
141
+ }
142
+ }
143
+
144
+ private handleMapChange = (event: Y.YMapEvent<any>) => {
145
+
146
+ if (event.keysChanged.has(ContainerKeys.scale) ||
147
+ event.keysChanged.has(ContainerKeys.translateX) ||
148
+ event.keysChanged.has(ContainerKeys.translateY)
149
+ ) {
150
+ this.updateSyncedTransform();
151
+ }
152
+
153
+ if (event.keysChanged.has(ContainerKeys.pageIndex)) {
154
+ this.handleGoto(this.pageIndex)
155
+ .catch(error => {
156
+ // todo error
157
+ });
158
+ }
159
+ };
160
+
161
+ public goto(index: number) {
162
+ let nextIndex = Math.max(0, index);
163
+ nextIndex = Math.min(this.images.length - 1, nextIndex);
164
+ this.map.set(ContainerKeys.pageIndex, nextIndex);
165
+ }
166
+
167
+ public append(image: LazyImage) {
168
+ this.images.push(image);
169
+ }
170
+
171
+ private async handleGoto(index: number): Promise<void> {
172
+ await waitUntil(() => this.images.length > 0, 3000);
173
+ if (index < 0 || index >= this.images.length) {
174
+ return;
175
+ }
176
+ this.imageDoc.emit("renderStart", index);
177
+ if (this.view.children[0]) {
178
+ this.view.removeChild(this.view.children[0]);
179
+ }
180
+ this.whiteboardApp.emitter.view.style.opacity = "0";
181
+ const target = this.images[index];
182
+ if (target) {
183
+ await target.prepare();
184
+ this.view.appendChild(target.view);
185
+ this.currentImage = target;
186
+ this.whiteboardApp.emitter.gotoPage(`doc_${index}`);
187
+ this.whiteboardApp.updateOptionSize(
188
+ this.currentImage.width,
189
+ this.currentImage.height
190
+ );
191
+ this.whiteboardApp.emitter.view.style.opacity = "1";
192
+ this.handleResize();
193
+ }
194
+ this.imageDoc.emit("renderEnd", index);
195
+ for (let i = index - 3; i <= index + 3; i++) {
196
+ const img = this.images[i];
197
+ if (img) {
198
+ img.prepare();
199
+ }
200
+ }
201
+ }
202
+
203
+ private handleResize = () => {
204
+ const bound = this.parentView.getBoundingClientRect();
205
+ if (this.currentImage) {
206
+ let scale = bound.width / this.currentImage.width;
207
+ if (this.currentImage.height * scale > bound.height) {
208
+ scale = bound.height / this.currentImage.height;
209
+ }
210
+ const tx = Math.round((bound.width - this.currentImage.width * scale) / 2 / scale);
211
+ const ty = Math.round((bound.height - this.currentImage.height * scale) / 2 / scale);
212
+ this.currentImage.view.style.transform = `scale(${scale}) translate(${tx}px, ${ty}px)`;
213
+ this.updateSyncedTransform();
214
+ }
215
+ }
216
+
217
+ private updateSyncedTransform = () => {
218
+ if (!this.currentImage) {
219
+ return;
220
+ }
221
+ const parentBounds = this.parentView.getBoundingClientRect();
222
+ const tx = -this.translateX * parentBounds.width / this.scale;
223
+ const ty = -this.translateY * parentBounds.height / this.scale;
224
+ this.view.style.transform = `scale(${this.scale}) translate(${tx}px, ${ty}px)`;
225
+ const whiteboardView = this.whiteboardApp.emitter.view;
226
+ whiteboardView.style.width = `${parentBounds.width}px`;
227
+ whiteboardView.style.height = `${parentBounds.height}px`;
228
+ whiteboardView.style.top = "0";
229
+ whiteboardView.style.left = "0";
230
+ whiteboardView.style.transform = `scale(${this.scale}) translate(${tx}px, ${ty}px)`;
231
+ this.whiteboardApp.adjustByOutFrame(parentBounds.width, parentBounds.height);
232
+ window.clearTimeout(this.timeoutId);
233
+ this.timeoutId = window.setTimeout(() => {
234
+ whiteboardView.style.width = `${parentBounds.width * this.scale}px`;
235
+ whiteboardView.style.height = `${parentBounds.height * this.scale}px`;
236
+ whiteboardView.style.top = `${-(this.scale - 1) * parentBounds.height / 2 + ty * this.scale}px`;
237
+ whiteboardView.style.left = `${-(this.scale - 1) * parentBounds.width / 2 + tx * this.scale}px`;
238
+ whiteboardView.style.transform = `scale(1) translate(0px, 0px)`;
239
+ this.whiteboardApp.adjustByOutFrame(parentBounds.width * this.scale, parentBounds.height * this.scale);
240
+ }, 200);
241
+ }
242
+
243
+ public dispose() {
244
+ this.resizeObserver.disconnect();
245
+ this.scroll.dispose();
246
+ window.clearTimeout(this.timeoutId);
247
+ }
248
+ }
package/src/icons.ts ADDED
@@ -0,0 +1,9 @@
1
+ const chevronLeft = (color: string) => `<svg style="width:100%;height:100%;padding:2px;box-sizing:border-box;" viewBox="0 0 12.3926 16.9629"><g><rect height="16.9629" opacity="0" width="12.3926" x="0" y="0"/><path d="M0 8.47656C0 8.7207 0.0878906 8.93555 0.273438 9.12109L8.01758 16.6895C8.18359 16.8652 8.39844 16.9531 8.65234 16.9531C9.16016 16.9531 9.55078 16.5723 9.55078 16.0645C9.55078 15.8105 9.44336 15.5957 9.28711 15.4297L2.17773 8.47656L9.28711 1.52344C9.44336 1.35742 9.55078 1.13281 9.55078 0.888672C9.55078 0.380859 9.16016 0 8.65234 0C8.39844 0 8.18359 0.0878906 8.01758 0.253906L0.273438 7.83203C0.0878906 8.00781 0 8.23242 0 8.47656Z" fill="${color}"/></g></svg>`;
2
+ const chevronRight = (color: string) => `<svg style="width:100%;height:100%;padding:2px;box-sizing:border-box;" viewBox="0 0 11.6895 16.9629"><g><rect height="16.9629" opacity="0" width="11.6895" x="0" y="0"/><path d="M11.6895 8.47656C11.6895 8.23242 11.5918 8.00781 11.4062 7.83203L3.67188 0.253906C3.49609 0.0878906 3.28125 0 3.02734 0C2.5293 0 2.13867 0.380859 2.13867 0.888672C2.13867 1.13281 2.23633 1.35742 2.39258 1.52344L9.50195 8.47656L2.39258 15.4297C2.23633 15.5957 2.13867 15.8105 2.13867 16.0645C2.13867 16.5723 2.5293 16.9531 3.02734 16.9531C3.28125 16.9531 3.49609 16.8652 3.67188 16.6895L11.4062 9.12109C11.5918 8.93555 11.6895 8.7207 11.6895 8.47656Z" fill="${color}"/></g></svg>`;
3
+ const sideBar = (color: string) => `<svg style="width:100%;height:100%;padding:2px;box-sizing:border-box;" viewBox="0 0 23.3887 17.998"><g><rect height="17.998" opacity="0" width="23.3887" x="0" y="0"/><path d="M3.06641 17.998L19.9609 17.998C22.0117 17.998 23.0273 16.9824 23.0273 14.9707L23.0273 3.04688C23.0273 1.03516 22.0117 0.0195312 19.9609 0.0195312L3.06641 0.0195312C1.02539 0.0195312 0 1.02539 0 3.04688L0 14.9707C0 16.9922 1.02539 17.998 3.06641 17.998ZM3.08594 16.4258C2.10938 16.4258 1.57227 15.9082 1.57227 14.8926L1.57227 3.125C1.57227 2.10938 2.10938 1.5918 3.08594 1.5918L19.9414 1.5918C20.9082 1.5918 21.4551 2.10938 21.4551 3.125L21.4551 14.8926C21.4551 15.9082 20.9082 16.4258 19.9414 16.4258ZM7.44141 16.7285L8.97461 16.7285L8.97461 1.29883L7.44141 1.29883ZM5.56641 5.21484C5.85938 5.21484 6.12305 4.95117 6.12305 4.66797C6.12305 4.375 5.85938 4.12109 5.56641 4.12109L3.4668 4.12109C3.17383 4.12109 2.91992 4.375 2.91992 4.66797C2.91992 4.95117 3.17383 5.21484 3.4668 5.21484ZM5.56641 7.74414C5.85938 7.74414 6.12305 7.48047 6.12305 7.1875C6.12305 6.89453 5.85938 6.65039 5.56641 6.65039L3.4668 6.65039C3.17383 6.65039 2.91992 6.89453 2.91992 7.1875C2.91992 7.48047 3.17383 7.74414 3.4668 7.74414ZM5.56641 10.2637C5.85938 10.2637 6.12305 10.0195 6.12305 9.72656C6.12305 9.43359 5.85938 9.17969 5.56641 9.17969L3.4668 9.17969C3.17383 9.17969 2.91992 9.43359 2.91992 9.72656C2.91992 10.0195 3.17383 10.2637 3.4668 10.2637Z" fill="${color}"/></g></svg>`;
4
+
5
+ export const Icons = {
6
+ chevronLeft,
7
+ chevronRight,
8
+ sideBar,
9
+ };
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { ImageryDoc } from "./ImageryDoc";
2
+ export { ImageryDocApplication } from "./ImageryDocApplication";
3
+ export { ImageryDocPermissionFlag } from "./ImageryDocPermissions";
4
+
5
+ export type { ImageryDocOption } from "./ImageryDocApplication";
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "include": ["src/**/*", "node_modules/paper/dist/paper.d.ts"],
4
+ "compilerOptions": {
5
+ "outDir": "dist"
6
+ }
7
+ }