@netless/forge-imagery-doc 0.1.1 → 0.1.3

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.
@@ -1,248 +1,258 @@
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";
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
7
 
8
8
  export const delay = (value: number) => new Promise(resolve => setTimeout(resolve, value));
9
9
 
10
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
- }
11
+ let start = Date.now();
12
+ while (!fn() && Date.now() - start < timeout) {
13
+ await delay(50);
14
+ start = Date.now();
15
+ }
16
16
  }
17
17
 
18
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;
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 imageDoc: ImageryDoc;
28
+
29
+ private get scale(): number {
30
+ return this.map.get(ContainerKeys.scale);
31
+ }
32
+ private set scale(value: number) {
33
+ this.map.set(ContainerKeys.scale, value);
34
+ }
35
+ private get translateX(): number {
36
+ return this.map.get(ContainerKeys.translateX);
37
+ }
38
+ private set translateX(value: number) {
39
+ this.map.set(ContainerKeys.translateX, value);
40
+ }
41
+ private get translateY(): number {
42
+ return this.map.get(ContainerKeys.translateY);
43
+ }
44
+ private set translateY(value: number) {
45
+ this.map.set(ContainerKeys.translateY, value);
46
+ }
47
+ public get pageIndex(): number {
48
+ return this.map.get(ContainerKeys.pageIndex);
49
+ }
50
+
51
+ public constructor(
52
+ map: Y.Map<any>,
53
+ whiteboardApp: WhiteboardApplication,
54
+ parentView: HTMLDivElement,
55
+ imageDoc: ImageryDoc,
56
+ ) {
57
+ this.imageDoc = imageDoc;
58
+ this.parentView = parentView;
59
+ this.map = map;
60
+ this.scroll = new InfinityScroll(this.parentView);
61
+ this.whiteboardApp = whiteboardApp;
62
+ this.view = document.createElement('div');
63
+ this.view.style.width = '100%';
64
+ this.view.style.height = '100%';
65
+ this.view.style.position = 'absolute';
66
+ this.view.style.top = '0';
67
+ this.view.style.left = '0';
68
+ this.view.style.transformOrigin = 'center';
69
+ this.view.setAttribute('data-imagery-container', 'single');
70
+
71
+ this.resizeObserver = new ResizeObserver(this.handleResize);
72
+ this.resizeObserver.observe(this.view);
29
73
 
30
- private get scale(): number {
31
- return this.map.get(ContainerKeys.scale);
74
+ this.whiteboardApp.updateInternalResizeObserverStatus(false);
75
+ this.map.observe(this.handleMapChange);
76
+ if (!this.map.has(ContainerKeys.scale)) {
77
+ this.map.set(ContainerKeys.scale, 1);
32
78
  }
33
- private set scale(value: number) {
34
- this.map.set(ContainerKeys.scale, value);
79
+ if (!this.map.has(ContainerKeys.translateX)) {
80
+ this.map.set(ContainerKeys.translateX, 0);
35
81
  }
36
- private get translateX(): number {
37
- return this.map.get(ContainerKeys.translateX);
82
+ if (!this.map.has(ContainerKeys.translateY)) {
83
+ this.map.set(ContainerKeys.translateY, 0);
38
84
  }
39
- private set translateX(value: number) {
40
- this.map.set(ContainerKeys.translateX, value);
85
+ if (!this.map.has(ContainerKeys.pageIndex)) {
86
+ this.map.set(ContainerKeys.pageIndex, 0);
41
87
  }
42
- private get translateY(): number {
43
- return this.map.get(ContainerKeys.translateY);
88
+ this.scroll.on('translate', (dx, dy) => {
89
+ this.handleTranslate(dx, dy);
90
+ });
91
+ this.scroll.on('scale', (scale) => {
92
+ let nextScale = this.scale * scale;
93
+ nextScale = Math.max(1, nextScale);
94
+ nextScale = Math.min(2, nextScale);
95
+ this.scale = nextScale;
96
+ this.handleTranslate(0, 0);
97
+ });
98
+ //@ts-ignore
99
+ window.__doc = this;
100
+ }
101
+
102
+ public init() {
103
+ this.handleGoto(this.pageIndex)
104
+ .catch(_error => {
105
+ // todo error
106
+ });
107
+ this.updateSyncedTransform();
108
+ }
109
+
110
+ private resetTranslateOnResize() {
111
+ const image = this.view.children[0];
112
+ if (!image) {
113
+ return;
44
114
  }
45
- private set translateY(value: number) {
46
- this.map.set(ContainerKeys.translateY, value);
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
+ if (maxDx < 0) {
120
+ this.translateX = 0;
47
121
  }
48
- public get pageIndex(): number {
49
- return this.map.get(ContainerKeys.pageIndex);
122
+ if (maxDy < 0) {
123
+ this.translateY = 0;
50
124
  }
125
+ }
51
126
 
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
- });
127
+ private handleTranslate(dx: number, dy: number) {
128
+ const image = this.view.children[0];
129
+ if (!image) {
130
+ return;
131
+ }
132
+ const imageBounds = image.getBoundingClientRect();
133
+ const parentBounds = this.parentView.getBoundingClientRect();
134
+ const maxDx = (imageBounds.width - parentBounds.width) / 2;
135
+ const maxDy = (imageBounds.height - parentBounds.height) / 2;
136
+
137
+ if (maxDx > 0) {
138
+ let nextDx = this.translateX * parentBounds.width + dx;
139
+ if (nextDx >= 0) {
140
+ nextDx = Math.min(nextDx, maxDx);
141
+ } else {
142
+ nextDx = Math.max(nextDx, -maxDx);
143
+ }
144
+ this.translateX = nextDx / parentBounds.width;
145
+ } else {
146
+ this.translateX = 0;
147
+ }
148
+ if (maxDy > 0) {
149
+ let nextDy = this.translateY * parentBounds.height + dy;
150
+ if (nextDy >= 0) {
151
+ nextDy = Math.min(nextDy, maxDy);
152
+ } else {
153
+ nextDy = Math.max(nextDy, -maxDy);
154
+ }
155
+ this.translateY = nextDy / parentBounds.height;
156
+ } else {
157
+ this.translateY = 0;
100
158
  }
159
+ }
101
160
 
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) ||
161
+ private handleMapChange = (event: Y.YMapEvent<any>) => {
162
+
163
+ if (event.keysChanged.has(ContainerKeys.scale) ||
147
164
  event.keysChanged.has(ContainerKeys.translateX) ||
148
165
  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);
166
+ ) {
167
+ this.updateSyncedTransform();
247
168
  }
169
+
170
+ if (event.keysChanged.has(ContainerKeys.pageIndex)) {
171
+ this.handleGoto(this.pageIndex)
172
+ .catch(_error => {
173
+ // todo error
174
+ });
175
+ }
176
+ };
177
+
178
+ public goto(index: number) {
179
+ let nextIndex = Math.max(0, index);
180
+ nextIndex = Math.min(this.images.length - 1, nextIndex);
181
+ this.map.set(ContainerKeys.pageIndex, nextIndex);
182
+ }
183
+
184
+ public append(image: LazyImage) {
185
+ this.images.push(image);
186
+ }
187
+
188
+ private async handleGoto(index: number): Promise<void> {
189
+ await waitUntil(() => this.images.length > 0, 3000);
190
+ if (index < 0 || index >= this.images.length) {
191
+ return;
192
+ }
193
+ this.imageDoc.emit('renderStart', index);
194
+ if (this.view.children[0]) {
195
+ this.view.removeChild(this.view.children[0]);
196
+ }
197
+ this.whiteboardApp.emitter.view.style.opacity = '0';
198
+ const target = this.images[index];
199
+ if (target) {
200
+ await target.prepare();
201
+ this.view.appendChild(target.view);
202
+ this.currentImage = target;
203
+ this.whiteboardApp.emitter.gotoPage(`doc_${index}`);
204
+ this.whiteboardApp.updateOptionSize(
205
+ this.currentImage.width,
206
+ this.currentImage.height,
207
+ );
208
+ this.whiteboardApp.emitter.view.style.opacity = '1';
209
+ this.handleResize();
210
+ }
211
+ this.imageDoc.emit('renderEnd', index);
212
+ for (let i = index - 3; i <= index + 3; i++) {
213
+ const img = this.images[i];
214
+ if (img) {
215
+ img.prepare();
216
+ }
217
+ }
218
+ }
219
+
220
+ private handleResize = () => {
221
+ const bound = this.parentView.getBoundingClientRect();
222
+ if (this.currentImage) {
223
+ let scale = bound.width / this.currentImage.width;
224
+ if (this.currentImage.height * scale > bound.height) {
225
+ scale = bound.height / this.currentImage.height;
226
+ }
227
+ const tx = Math.round((bound.width - this.currentImage.width * scale) / 2 / scale);
228
+ const ty = Math.round((bound.height - this.currentImage.height * scale) / 2 / scale);
229
+ this.currentImage.view.style.transform = `scale(${scale}) translate(${tx}px, ${ty}px)`;
230
+ this.updateSyncedTransform();
231
+ this.resetTranslateOnResize();
232
+ }
233
+ };
234
+
235
+ private updateSyncedTransform = () => {
236
+ if (!this.currentImage) {
237
+ return;
238
+ }
239
+ const parentBounds = this.parentView.getBoundingClientRect();
240
+ const tx = -this.translateX * parentBounds.width / this.scale;
241
+ const ty = -this.translateY * parentBounds.height / this.scale;
242
+ this.view.style.transform = `scale(${this.scale}) translate(${tx}px, ${ty}px)`;
243
+ this.whiteboardApp.adjustByOutFrame(parentBounds.width * this.scale, parentBounds.height * this.scale);
244
+ const whiteboardSize = this.whiteboardApp.getViewSize();
245
+ const whiteboardScale = this.whiteboardApp.getInherentScale();
246
+ this.whiteboardApp.emitter.resetCamera();
247
+ this.whiteboardApp.emitter.translateCamera(
248
+ -this.translateX * whiteboardSize[0] / whiteboardScale / this.scale,
249
+ -this.translateY * whiteboardSize[1] / whiteboardScale / this.scale,
250
+ );
251
+ };
252
+
253
+ public dispose() {
254
+ this.map.unobserve(this.handleMapChange);
255
+ this.resizeObserver.disconnect();
256
+ this.scroll.dispose();
257
+ }
248
258
  }
package/src/icons.ts CHANGED
@@ -3,7 +3,7 @@ const chevronRight = (color: string) => `<svg style="width:100%;height:100%;padd
3
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
4
 
5
5
  export const Icons = {
6
- chevronLeft,
7
- chevronRight,
8
- sideBar,
6
+ chevronLeft,
7
+ chevronRight,
8
+ sideBar,
9
9
  };
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { ImageryDoc } from "./ImageryDoc";
2
- export { ImageryDocApplication } from "./ImageryDocApplication";
3
- export { ImageryDocPermissionFlag } from "./ImageryDocPermissions";
1
+ export { ImageryDoc } from './ImageryDoc';
2
+ export { ImageryDocApplication } from './ImageryDocApplication';
3
+ export { ImageryDocPermissionFlag } from './ImageryDocPermissions';
4
4
 
5
- export type { ImageryDocOption } from "./ImageryDocApplication";
5
+ export type { ImageryDocOption } from './ImageryDocApplication';