@univerjs/docs-drawing 1.0.0-alpha.3 → 1.0.0-alpha.5

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.
@@ -0,0 +1,558 @@
1
+ import { ArrangeTypeEnum, BooleanNumber, DrawingTypeEnum, ICommandService, IImageIoService, IURLImageService, ImageSourceType, ObjectRelativeFromH, ObjectRelativeFromV, WrapTextType, generateRandomId } from "@univerjs/core";
2
+ import { buildDocTransform, docDrawingPositionToTransform } from "@univerjs/docs";
3
+ import { InsertDocDrawingCommand, RemoveDocDrawingCommand, SetDocDrawingArrangeCommand, TextWrappingStyle, UpdateDocDrawingWrappingStyleCommand, UpdateDrawingDocTransformCommand, WRAPPING_STYLE_TO_LAYOUT_TYPE } from "@univerjs/docs-drawing";
4
+ import { FDocument } from "@univerjs/docs/facade";
5
+ import { DRAWING_IMAGE_HEIGHT_LIMIT, DRAWING_IMAGE_WIDTH_LIMIT, getImageSize } from "@univerjs/drawing";
6
+ import { FEnum } from "@univerjs/core/facade";
7
+
8
+ //#region src/facade/f-document-image.ts
9
+ /**
10
+ * Facade API for an image in a document.
11
+ * @hideconstructor
12
+ */
13
+ var FDocumentImage = class {
14
+ constructor(_document, _imageId, _injector) {
15
+ this._document = _document;
16
+ this._imageId = _imageId;
17
+ this._injector = _injector;
18
+ }
19
+ /**
20
+ * Gets the id of the document containing the image.
21
+ * @returns {string} The document unit id.
22
+ * @example
23
+ * ```ts
24
+ * const fDocument = univerAPI.getActiveDocument();
25
+ * const image = fDocument.getImages()[0];
26
+ *
27
+ * if (image) {
28
+ * console.log(image.getUnitId());
29
+ * }
30
+ * ```
31
+ */
32
+ getUnitId() {
33
+ return this._document.getId();
34
+ }
35
+ /**
36
+ * Gets the drawing id of the image.
37
+ * @returns {string} The drawing id.
38
+ * @example
39
+ * ```ts
40
+ * const fDocument = univerAPI.getActiveDocument();
41
+ * const image = fDocument.getImages()[0];
42
+ *
43
+ * if (image) {
44
+ * console.log(image.getId());
45
+ * }
46
+ * ```
47
+ */
48
+ getId() {
49
+ return this._imageId;
50
+ }
51
+ /**
52
+ * Gets the image source supplied at insertion time.
53
+ * @returns {string | undefined} The image source, or `undefined` when the image no longer exists.
54
+ * @example
55
+ * ```ts
56
+ * const fDocument = univerAPI.getActiveDocument();
57
+ * const image = fDocument.getImages()[0];
58
+ *
59
+ * if (image) {
60
+ * console.log(image.getSource());
61
+ * }
62
+ * ```
63
+ */
64
+ getSource() {
65
+ var _this$getImageData;
66
+ return (_this$getImageData = this.getImageData()) === null || _this$getImageData === void 0 ? void 0 : _this$getImageData.source;
67
+ }
68
+ /**
69
+ * Gets the image source type supplied at insertion time.
70
+ * @returns {ImageSourceType | undefined} The image source type, or `undefined` when the image no longer exists.
71
+ * @example
72
+ * ```ts
73
+ * const fDocument = univerAPI.getActiveDocument();
74
+ * const image = fDocument.getImages()[0];
75
+ *
76
+ * if (image) {
77
+ * console.log(image.getSourceType());
78
+ * }
79
+ * ```
80
+ */
81
+ getSourceType() {
82
+ var _this$getImageData2;
83
+ return (_this$getImageData2 = this.getImageData()) === null || _this$getImageData2 === void 0 ? void 0 : _this$getImageData2.imageSourceType;
84
+ }
85
+ /**
86
+ * Gets the current image size.
87
+ * @returns {ISize | null} The width and height in pixels, or `null` when the image no longer exists.
88
+ * @example
89
+ * ```ts
90
+ * const fDocument = univerAPI.getActiveDocument();
91
+ * const image = fDocument.getImages()[0];
92
+ *
93
+ * if (image) {
94
+ * console.log(image.getSize());
95
+ * }
96
+ * ```
97
+ */
98
+ getSize() {
99
+ var _this$getImageData$do, _this$getImageData3;
100
+ return (_this$getImageData$do = (_this$getImageData3 = this.getImageData()) === null || _this$getImageData3 === void 0 ? void 0 : _this$getImageData3.docTransform.size) !== null && _this$getImageData$do !== void 0 ? _this$getImageData$do : null;
101
+ }
102
+ /**
103
+ * Gets the current clockwise rotation angle.
104
+ * @returns {number | undefined} The rotation angle in degrees, or `undefined` when the image no longer exists.
105
+ * @example
106
+ * ```ts
107
+ * const fDocument = univerAPI.getActiveDocument();
108
+ * const image = fDocument.getImages()[0];
109
+ *
110
+ * if (image) {
111
+ * console.log(image.getAngle());
112
+ * }
113
+ * ```
114
+ */
115
+ getAngle() {
116
+ var _this$getImageData4;
117
+ return (_this$getImageData4 = this.getImageData()) === null || _this$getImageData4 === void 0 ? void 0 : _this$getImageData4.docTransform.angle;
118
+ }
119
+ /**
120
+ * Gets the current horizontal position.
121
+ * @returns {IObjectPositionH | null} The horizontal position, or `null` when the image no longer exists.
122
+ * @example
123
+ * ```ts
124
+ * const fDocument = univerAPI.getActiveDocument();
125
+ * const image = fDocument.getImages()[0];
126
+ *
127
+ * if (image) {
128
+ * console.log(image.getPositionH());
129
+ * }
130
+ * ```
131
+ */
132
+ getPositionH() {
133
+ var _this$getImageData$do2, _this$getImageData5;
134
+ return (_this$getImageData$do2 = (_this$getImageData5 = this.getImageData()) === null || _this$getImageData5 === void 0 ? void 0 : _this$getImageData5.docTransform.positionH) !== null && _this$getImageData$do2 !== void 0 ? _this$getImageData$do2 : null;
135
+ }
136
+ /**
137
+ * Gets the current vertical position.
138
+ * @returns {IObjectPositionV | null} The vertical position, or `null` when the image no longer exists.
139
+ * @example
140
+ * ```ts
141
+ * const fDocument = univerAPI.getActiveDocument();
142
+ * const image = fDocument.getImages()[0];
143
+ *
144
+ * if (image) {
145
+ * console.log(image.getPositionV());
146
+ * }
147
+ * ```
148
+ */
149
+ getPositionV() {
150
+ var _this$getImageData$do3, _this$getImageData6;
151
+ return (_this$getImageData$do3 = (_this$getImageData6 = this.getImageData()) === null || _this$getImageData6 === void 0 ? void 0 : _this$getImageData6.docTransform.positionV) !== null && _this$getImageData$do3 !== void 0 ? _this$getImageData$do3 : null;
152
+ }
153
+ /**
154
+ * Gets the current raw document image data.
155
+ * @returns {IDocImage | null} The image data, or `null` when the image no longer exists.
156
+ * @example
157
+ * ```ts
158
+ * const fDocument = univerAPI.getActiveDocument();
159
+ * const image = fDocument.getImages()[0];
160
+ *
161
+ * if (image) {
162
+ * console.log(image.getImageData());
163
+ * }
164
+ * ```
165
+ */
166
+ getImageData() {
167
+ var _this$_document$getDo;
168
+ const drawing = (_this$_document$getDo = this._document.getDocumentDataModel().getDrawings()) === null || _this$_document$getDo === void 0 ? void 0 : _this$_document$getDo[this._imageId];
169
+ if (!drawing || drawing.drawingType !== DrawingTypeEnum.DRAWING_IMAGE) return null;
170
+ return drawing;
171
+ }
172
+ /**
173
+ * Sets the image size.
174
+ * @param {number} width The width in pixels.
175
+ * @param {number} height The height in pixels.
176
+ * @returns {boolean} `true` when the update command succeeds; otherwise, `false`.
177
+ * @example
178
+ * ```ts
179
+ * const fDocument = univerAPI.getActiveDocument();
180
+ * const image = fDocument.getImages()[0];
181
+ *
182
+ * if (image) {
183
+ * const success = image.setSize(400, 300);
184
+ * console.log(success);
185
+ * }
186
+ * ```
187
+ */
188
+ setSize(width, height) {
189
+ return this._updateTransform("size", {
190
+ width,
191
+ height
192
+ });
193
+ }
194
+ /**
195
+ * Sets the clockwise rotation angle.
196
+ * @param {number} angle The rotation angle in degrees.
197
+ * @returns {boolean} `true` when the update command succeeds; otherwise, `false`.
198
+ * @example
199
+ * ```ts
200
+ * const fDocument = univerAPI.getActiveDocument();
201
+ * const image = fDocument.getImages()[0];
202
+ *
203
+ * if (image) {
204
+ * const success = image.setRotate(45);
205
+ * console.log(success);
206
+ * }
207
+ * ```
208
+ */
209
+ setRotate(angle) {
210
+ return this._updateTransform("angle", angle);
211
+ }
212
+ /**
213
+ * Sets the horizontal position of the image.
214
+ * Inline images are positioned by their document placeholder, so this has a visible effect only when the image
215
+ * wrapping style is not `TextWrappingStyle.INLINE`.
216
+ * @param {IObjectPositionH} positionH The horizontal position relative to the document.
217
+ * @returns {boolean} `true` when the update command succeeds; otherwise, `false`.
218
+ * @example
219
+ * ```ts
220
+ * const fDocument = univerAPI.getActiveDocument();
221
+ * const image = fDocument.getImages()[0];
222
+ *
223
+ * if (image) {
224
+ * const success = image.setPositionH({
225
+ * relativeFrom: univerAPI.Enum.DocsImageRelativeFromH.MARGIN,
226
+ * posOffset: 100
227
+ * });
228
+ * console.log(success);
229
+ * }
230
+ * ```
231
+ */
232
+ setPositionH(positionH) {
233
+ return this._updateTransform("positionH", positionH);
234
+ }
235
+ /**
236
+ * Sets the vertical position of the image.
237
+ * Inline images are positioned by their document placeholder, so this has a visible effect only when the image
238
+ * wrapping style is not `TextWrappingStyle.INLINE`.
239
+ * @param {IObjectPositionV} positionV The vertical position relative to the document.
240
+ * @returns {boolean} `true` when the update command succeeds; otherwise, `false`.
241
+ * @example
242
+ * ```ts
243
+ * const fDocument = univerAPI.getActiveDocument();
244
+ * const image = fDocument.getImages()[0];
245
+ *
246
+ * if (image) {
247
+ * const success = image.setPositionV({
248
+ * relativeFrom: univerAPI.Enum.DocsImageRelativeFromV.MARGIN,
249
+ * posOffset: 100
250
+ * });
251
+ * console.log(success);
252
+ * }
253
+ * ```
254
+ */
255
+ setPositionV(positionV) {
256
+ return this._updateTransform("positionV", positionV);
257
+ }
258
+ /**
259
+ * Sets the image wrapping style.
260
+ * When switching from inline to a floating style in a UI environment, the current visual position is preserved.
261
+ * @param {TextWrappingStyle} wrappingStyle The wrapping style to apply.
262
+ * @returns {boolean} `true` when the update command succeeds; otherwise, `false`.
263
+ * @example
264
+ * ```ts
265
+ * const fDocument = univerAPI.getActiveDocument();
266
+ * const image = fDocument.getImages()[0];
267
+ *
268
+ * if (image) {
269
+ * const success = image.setWrappingStyle(univerAPI.Enum.DocsImageWrappingStyle.WRAP_SQUARE);
270
+ * console.log(success);
271
+ * }
272
+ * ```
273
+ */
274
+ setWrappingStyle(wrappingStyle) {
275
+ const image = this.getImageData();
276
+ if (!image) return false;
277
+ return this._injector.get(ICommandService).syncExecuteCommand(UpdateDocDrawingWrappingStyleCommand.id, {
278
+ unitId: this.getUnitId(),
279
+ subUnitId: this.getUnitId(),
280
+ drawings: [image],
281
+ wrappingStyle
282
+ });
283
+ }
284
+ /**
285
+ * Moves the image forward by one level in the drawing order.
286
+ * @returns {boolean} `true` when the arrange command succeeds; otherwise, `false`.
287
+ * @example
288
+ * ```ts
289
+ * const fDocument = univerAPI.getActiveDocument();
290
+ * const image = fDocument.getImages()[0];
291
+ *
292
+ * if (image) {
293
+ * const success = image.setForward();
294
+ * console.log(success);
295
+ * }
296
+ * ```
297
+ */
298
+ setForward() {
299
+ return this._arrange(ArrangeTypeEnum.forward);
300
+ }
301
+ /**
302
+ * Moves the image backward by one level in the drawing order.
303
+ * @returns {boolean} `true` when the arrange command succeeds; otherwise, `false`.
304
+ * @example
305
+ * ```ts
306
+ * const fDocument = univerAPI.getActiveDocument();
307
+ * const image = fDocument.getImages()[0];
308
+ *
309
+ * if (image) {
310
+ * const success = image.setBackward();
311
+ * console.log(success);
312
+ * }
313
+ * ```
314
+ */
315
+ setBackward() {
316
+ return this._arrange(ArrangeTypeEnum.backward);
317
+ }
318
+ /**
319
+ * Moves the image to the back of the drawing order.
320
+ * @returns {boolean} `true` when the arrange command succeeds; otherwise, `false`.
321
+ * @example
322
+ * ```ts
323
+ * const fDocument = univerAPI.getActiveDocument();
324
+ * const image = fDocument.getImages()[0];
325
+ *
326
+ * if (image) {
327
+ * const success = image.setBack();
328
+ * console.log(success);
329
+ * }
330
+ * ```
331
+ */
332
+ setBack() {
333
+ return this._arrange(ArrangeTypeEnum.back);
334
+ }
335
+ /**
336
+ * Moves the image to the front of the drawing order.
337
+ * @returns {boolean} `true` when the arrange command succeeds; otherwise, `false`.
338
+ * @example
339
+ * ```ts
340
+ * const fDocument = univerAPI.getActiveDocument();
341
+ * const image = fDocument.getImages()[0];
342
+ *
343
+ * if (image) {
344
+ * const success = image.setFront();
345
+ * console.log(success);
346
+ * }
347
+ * ```
348
+ */
349
+ setFront() {
350
+ return this._arrange(ArrangeTypeEnum.front);
351
+ }
352
+ /**
353
+ * Removes the image and its document placeholder.
354
+ * @returns {boolean} `true` when the remove command succeeds; otherwise, `false`.
355
+ * @example
356
+ * ```ts
357
+ * const fDocument = univerAPI.getActiveDocument();
358
+ * const image = fDocument.getImages()[0];
359
+ *
360
+ * if (image) {
361
+ * const success = image.remove();
362
+ * console.log(success);
363
+ * }
364
+ * ```
365
+ */
366
+ remove() {
367
+ const image = this.getImageData();
368
+ const textRange = this._getTextRange();
369
+ if (!image || !textRange) return false;
370
+ return this._injector.get(ICommandService).syncExecuteCommand(RemoveDocDrawingCommand.id, {
371
+ unitId: this.getUnitId(),
372
+ drawings: [{
373
+ unitId: this.getUnitId(),
374
+ subUnitId: this.getUnitId(),
375
+ drawingId: this._imageId,
376
+ drawingType: DrawingTypeEnum.DRAWING_IMAGE
377
+ }],
378
+ textRange
379
+ });
380
+ }
381
+ _updateTransform(key, value) {
382
+ return this._injector.get(ICommandService).syncExecuteCommand(UpdateDrawingDocTransformCommand.id, {
383
+ unitId: this.getUnitId(),
384
+ subUnitId: this.getUnitId(),
385
+ drawings: [{
386
+ drawingId: this._imageId,
387
+ key,
388
+ value
389
+ }]
390
+ });
391
+ }
392
+ _arrange(arrangeType) {
393
+ return this._injector.get(ICommandService).syncExecuteCommand(SetDocDrawingArrangeCommand.id, {
394
+ unitId: this.getUnitId(),
395
+ subUnitId: this.getUnitId(),
396
+ drawingIds: [this._imageId],
397
+ arrangeType
398
+ });
399
+ }
400
+ _getTextRange() {
401
+ const { body, headers = {}, footers = {} } = this._document.getDocumentDataModel().getSnapshot();
402
+ const segments = [
403
+ {
404
+ segmentId: "",
405
+ body
406
+ },
407
+ ...Object.entries(headers).map(([segmentId, header]) => ({
408
+ segmentId,
409
+ body: header.body
410
+ })),
411
+ ...Object.entries(footers).map(([segmentId, footer]) => ({
412
+ segmentId,
413
+ body: footer.body
414
+ }))
415
+ ];
416
+ for (const { segmentId, body } of segments) {
417
+ var _body$customBlocks;
418
+ const customBlock = body === null || body === void 0 || (_body$customBlocks = body.customBlocks) === null || _body$customBlocks === void 0 ? void 0 : _body$customBlocks.find((block) => block.blockId === this._imageId);
419
+ if (customBlock) return {
420
+ startOffset: customBlock.startIndex,
421
+ endOffset: customBlock.startIndex,
422
+ collapsed: true,
423
+ segmentId
424
+ };
425
+ }
426
+ return null;
427
+ }
428
+ };
429
+
430
+ //#endregion
431
+ //#region src/facade/f-document.ts
432
+ var FDocumentImageMixin = class extends FDocument {
433
+ async insertImage(options) {
434
+ var _options$wrappingStyl, _options$angle, _options$positionH, _options$positionV;
435
+ const unitId = this.getId();
436
+ const imageId = generateRandomId(6);
437
+ const size = resolveImageSize(await this._getIntrinsicSize(options.source, options.imageSourceType), options);
438
+ const defaultTransform = buildDocTransform(size.width, size.height);
439
+ const wrappingStyle = (_options$wrappingStyl = options.wrappingStyle) !== null && _options$wrappingStyl !== void 0 ? _options$wrappingStyl : TextWrappingStyle.INLINE;
440
+ const docTransform = {
441
+ ...defaultTransform,
442
+ angle: (_options$angle = options.angle) !== null && _options$angle !== void 0 ? _options$angle : defaultTransform.angle,
443
+ positionH: (_options$positionH = options.positionH) !== null && _options$positionH !== void 0 ? _options$positionH : defaultTransform.positionH,
444
+ positionV: (_options$positionV = options.positionV) !== null && _options$positionV !== void 0 ? _options$positionV : defaultTransform.positionV
445
+ };
446
+ const transform = docDrawingPositionToTransform(docTransform);
447
+ const drawing = {
448
+ unitId,
449
+ subUnitId: unitId,
450
+ drawingId: imageId,
451
+ drawingType: DrawingTypeEnum.DRAWING_IMAGE,
452
+ imageSourceType: options.imageSourceType,
453
+ source: options.source,
454
+ transform,
455
+ docTransform,
456
+ behindDoc: wrappingStyle === TextWrappingStyle.BEHIND_TEXT ? BooleanNumber.TRUE : BooleanNumber.FALSE,
457
+ title: "",
458
+ description: "",
459
+ layoutType: WRAPPING_STYLE_TO_LAYOUT_TYPE[wrappingStyle],
460
+ wrapText: WrapTextType.BOTH_SIDES,
461
+ distB: 0,
462
+ distL: 0,
463
+ distR: 0,
464
+ distT: 0
465
+ };
466
+ if (!this._injector.get(ICommandService).syncExecuteCommand(InsertDocDrawingCommand.id, {
467
+ unitId,
468
+ drawings: [drawing],
469
+ textRange: options.textRange
470
+ })) return null;
471
+ return this._injector.createInstance(FDocumentImage, this, imageId, this._injector);
472
+ }
473
+ getImage(imageId) {
474
+ var _this$getDocumentData;
475
+ const drawing = (_this$getDocumentData = this.getDocumentDataModel().getDrawings()) === null || _this$getDocumentData === void 0 ? void 0 : _this$getDocumentData[imageId];
476
+ if (!drawing || drawing.drawingType !== DrawingTypeEnum.DRAWING_IMAGE) return null;
477
+ return this._injector.createInstance(FDocumentImage, this, imageId, this._injector);
478
+ }
479
+ getImages() {
480
+ var _documentDataModel$ge, _documentDataModel$ge2;
481
+ const documentDataModel = this.getDocumentDataModel();
482
+ const drawings = (_documentDataModel$ge = documentDataModel.getDrawings()) !== null && _documentDataModel$ge !== void 0 ? _documentDataModel$ge : {};
483
+ return ((_documentDataModel$ge2 = documentDataModel.getDrawingsOrder()) !== null && _documentDataModel$ge2 !== void 0 ? _documentDataModel$ge2 : Object.keys(drawings)).filter((drawingId) => {
484
+ var _drawings$drawingId;
485
+ return ((_drawings$drawingId = drawings[drawingId]) === null || _drawings$drawingId === void 0 ? void 0 : _drawings$drawingId.drawingType) === DrawingTypeEnum.DRAWING_IMAGE;
486
+ }).map((drawingId) => this._injector.createInstance(FDocumentImage, this, drawingId, this._injector));
487
+ }
488
+ async _getIntrinsicSize(source, imageSourceType) {
489
+ const imageIoService = this._injector.has(IImageIoService) ? this._injector.get(IImageIoService) : null;
490
+ let resolvedSource = source;
491
+ if (imageSourceType === ImageSourceType.UUID && imageIoService) resolvedSource = await imageIoService.getImage(source);
492
+ else if (imageSourceType === ImageSourceType.URL && this._injector.has(IURLImageService)) try {
493
+ resolvedSource = await this._injector.get(IURLImageService).getImage(source);
494
+ } catch {
495
+ resolvedSource = source;
496
+ }
497
+ const { width, height, image } = await getImageSize(resolvedSource);
498
+ imageIoService === null || imageIoService === void 0 || imageIoService.addImageSourceCache(source, imageSourceType, image);
499
+ return {
500
+ width,
501
+ height
502
+ };
503
+ }
504
+ };
505
+ function resolveImageSize(intrinsicSize, options) {
506
+ const { width: intrinsicWidth, height: intrinsicHeight } = intrinsicSize;
507
+ if (options.width != null && options.height != null) return {
508
+ width: options.width,
509
+ height: options.height
510
+ };
511
+ if (options.width != null) return {
512
+ width: options.width,
513
+ height: intrinsicHeight * options.width / intrinsicWidth
514
+ };
515
+ if (options.height != null) return {
516
+ width: intrinsicWidth * options.height / intrinsicHeight,
517
+ height: options.height
518
+ };
519
+ const scale = Math.min(1, DRAWING_IMAGE_WIDTH_LIMIT / intrinsicWidth, DRAWING_IMAGE_HEIGHT_LIMIT / intrinsicHeight);
520
+ return {
521
+ width: intrinsicWidth * scale,
522
+ height: intrinsicHeight * scale
523
+ };
524
+ }
525
+ FDocument.extend(FDocumentImageMixin);
526
+
527
+ //#endregion
528
+ //#region src/facade/f-enum.ts
529
+ /**
530
+ * Copyright 2023-present DreamNum Co., Ltd.
531
+ *
532
+ * Licensed under the Apache License, Version 2.0 (the "License");
533
+ * you may not use this file except in compliance with the License.
534
+ * You may obtain a copy of the License at
535
+ *
536
+ * http://www.apache.org/licenses/LICENSE-2.0
537
+ *
538
+ * Unless required by applicable law or agreed to in writing, software
539
+ * distributed under the License is distributed on an "AS IS" BASIS,
540
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
541
+ * See the License for the specific language governing permissions and
542
+ * limitations under the License.
543
+ */
544
+ var FDocumentImageEnumMixin = class extends FEnum {
545
+ get DocsImageWrappingStyle() {
546
+ return TextWrappingStyle;
547
+ }
548
+ get DocsImageRelativeFromH() {
549
+ return ObjectRelativeFromH;
550
+ }
551
+ get DocsImageRelativeFromV() {
552
+ return ObjectRelativeFromV;
553
+ }
554
+ };
555
+ FEnum.extend(FDocumentImageEnumMixin);
556
+
557
+ //#endregion
558
+ export { FDocumentImage };