@idraw/util 0.4.0-beta.0 → 0.4.0-beta.10

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,17 +1,19 @@
1
1
  export function downloadImageFromCanvas(canvas, opts) {
2
- const { filename, type = 'image/jpeg' } = opts;
2
+ const { fileName, type = 'image/jpeg' } = opts;
3
3
  const stream = canvas.toDataURL(type);
4
- const downloadLink = document.createElement('a');
4
+ let downloadLink = document.createElement('a');
5
5
  downloadLink.href = stream;
6
- downloadLink.download = filename;
7
- const downloadClickEvent = document.createEvent('MouseEvents');
8
- downloadClickEvent.initEvent('click', true, false);
9
- downloadLink.dispatchEvent(downloadClickEvent);
6
+ downloadLink.download = fileName;
7
+ downloadLink.click();
8
+ downloadLink = null;
10
9
  }
11
10
  export function pickFile(opts) {
12
- const { success, error } = opts;
11
+ const { accept, success, error } = opts;
13
12
  let input = document.createElement('input');
14
13
  input.type = 'file';
14
+ if (accept) {
15
+ input.accept = accept;
16
+ }
15
17
  input.addEventListener('change', function () {
16
18
  var _a;
17
19
  const file = (_a = input.files) === null || _a === void 0 ? void 0 : _a[0];
@@ -64,3 +66,20 @@ export function parseFileToText(file) {
64
66
  reader.readAsText(file);
65
67
  });
66
68
  }
69
+ export function parseTextToBlobURL(text) {
70
+ const bytes = new TextEncoder().encode(text);
71
+ const blob = new Blob([bytes], {
72
+ type: 'text/plain;charset=utf-8'
73
+ });
74
+ const blobURL = window.URL.createObjectURL(blob);
75
+ return blobURL;
76
+ }
77
+ export function downloadFileFromText(text, opts) {
78
+ const { fileName } = opts;
79
+ const blobURL = parseTextToBlobURL(text);
80
+ let downloadLink = document.createElement('a');
81
+ downloadLink.href = blobURL;
82
+ downloadLink.download = fileName;
83
+ downloadLink.click();
84
+ downloadLink = null;
85
+ }
@@ -1,10 +1,10 @@
1
1
  import { createUUID } from './uuid';
2
- import { getDefaultElementDetailConfig, getDefaultElementRectDetail, getDefaultElementCircleDetail, getDefaultElementTextDetail, getDefaultElementSVGDetail, getDefaultElementImageDetail, getDefaultElementGroupDetail } from './config';
2
+ import { defaultText, getDefaultElementRectDetail, getDefaultElementCircleDetail, getDefaultElementTextDetail, getDefaultElementSVGDetail, getDefaultElementImageDetail, getDefaultElementGroupDetail } from './config';
3
3
  import { istype } from './istype';
4
4
  import { findElementFromListByPosition, getElementPositionFromList } from './element';
5
+ import { deepResizeGroupElement } from './resize-element';
5
6
  const defaultViewWidth = 200;
6
7
  const defaultViewHeight = 200;
7
- const defaultDetail = getDefaultElementDetailConfig();
8
8
  function createElementSize(type, opts) {
9
9
  let x = 0;
10
10
  let y = 0;
@@ -14,29 +14,26 @@ function createElementSize(type, opts) {
14
14
  const { viewScaleInfo, viewSizeInfo } = opts;
15
15
  const { scale, offsetLeft, offsetTop } = viewScaleInfo;
16
16
  const { width, height } = viewSizeInfo;
17
- if (type === 'text') {
18
- const textDetail = getDefaultElementTextDetail();
19
- w = defaultDetail.fontSize * scale * textDetail.text.length;
20
- h = defaultDetail.fontSize * scale * 2;
17
+ const limitViewWidth = width / 4;
18
+ const limitViewHeight = height / 4;
19
+ if (defaultViewWidth >= limitViewWidth) {
20
+ w = limitViewWidth / scale;
21
21
  }
22
22
  else {
23
- const limitViewWidth = width / 4;
24
- const limitViewHeight = height / 4;
25
- if (defaultViewWidth >= limitViewWidth) {
26
- w = limitViewWidth / scale;
27
- }
28
- else {
29
- w = defaultViewWidth / scale;
30
- }
31
- if (defaultViewHeight >= limitViewHeight) {
32
- h = limitViewHeight / scale;
33
- }
34
- else {
35
- h = defaultViewHeight / scale;
36
- }
37
- if (['circle', 'svg', 'image'].includes(type)) {
38
- w = h = Math.max(w, h);
39
- }
23
+ w = defaultViewWidth / scale;
24
+ }
25
+ if (defaultViewHeight >= limitViewHeight) {
26
+ h = limitViewHeight / scale;
27
+ }
28
+ else {
29
+ h = defaultViewHeight / scale;
30
+ }
31
+ if (['circle', 'svg', 'image'].includes(type)) {
32
+ w = h = Math.max(w, h);
33
+ }
34
+ else if (type === 'text') {
35
+ const fontSize = w / defaultText.length;
36
+ h = fontSize * 2;
40
37
  }
41
38
  x = (0 - offsetLeft + width / 2 - (w * scale) / 2) / scale;
42
39
  y = (0 - offsetTop + height / 2 - (h * scale) / 2) / scale;
@@ -50,18 +47,16 @@ function createElementSize(type, opts) {
50
47
  return elemSize;
51
48
  }
52
49
  export function createElement(type, baseElem, opts) {
53
- const elemSize = createElementSize(type, opts);
50
+ const elementSize = createElementSize(type, opts);
54
51
  let detail = {};
55
52
  if (type === 'rect') {
56
53
  detail = getDefaultElementRectDetail();
57
54
  }
58
55
  else if (type === 'circle') {
59
- detail = getDefaultElementCircleDetail({
60
- radius: elemSize.w
61
- });
56
+ detail = getDefaultElementCircleDetail();
62
57
  }
63
58
  else if (type === 'text') {
64
- detail = getDefaultElementTextDetail(opts);
59
+ detail = getDefaultElementTextDetail(elementSize);
65
60
  }
66
61
  else if (type === 'svg') {
67
62
  detail = getDefaultElementSVGDetail();
@@ -72,7 +67,7 @@ export function createElement(type, baseElem, opts) {
72
67
  else if (type === 'group') {
73
68
  detail = getDefaultElementGroupDetail();
74
69
  }
75
- const elem = Object.assign(Object.assign(Object.assign({}, elemSize), baseElem), { uuid: createUUID(), type, detail: Object.assign(Object.assign({}, detail), (baseElem.detail || {})) });
70
+ const elem = Object.assign(Object.assign(Object.assign({}, elementSize), baseElem), { uuid: createUUID(), type, detail: Object.assign(Object.assign({}, detail), (baseElem.detail || {})) });
76
71
  return elem;
77
72
  }
78
73
  export function insertElementToListByPosition(element, position, list) {
@@ -209,17 +204,25 @@ function mergeElement(originElem, updateContent) {
209
204
  return originElem;
210
205
  }
211
206
  export function updateElementInList(uuid, updateContent, elements) {
212
- var _a;
207
+ var _a, _b;
213
208
  let targetElement = null;
214
209
  for (let i = 0; i < elements.length; i++) {
215
210
  const elem = elements[i];
216
211
  if (elem.uuid === uuid) {
212
+ if (elem.type === 'group' && ((_a = elem.operations) === null || _a === void 0 ? void 0 : _a.deepResize) === true) {
213
+ if ((updateContent.w && updateContent.w > 0) || (updateContent.h && updateContent.h > 0)) {
214
+ deepResizeGroupElement(elem, {
215
+ w: updateContent.w,
216
+ h: updateContent.h
217
+ });
218
+ }
219
+ }
217
220
  mergeElement(elem, updateContent);
218
221
  targetElement = elem;
219
222
  break;
220
223
  }
221
224
  else if (elem.type === 'group') {
222
- targetElement = updateElementInList(uuid, updateContent, ((_a = elem === null || elem === void 0 ? void 0 : elem.detail) === null || _a === void 0 ? void 0 : _a.children) || []);
225
+ targetElement = updateElementInList(uuid, updateContent, ((_b = elem === null || elem === void 0 ? void 0 : elem.detail) === null || _b === void 0 ? void 0 : _b.children) || []);
223
226
  }
224
227
  }
225
228
  return targetElement;
@@ -0,0 +1,2 @@
1
+ import type { Element, ElementSize } from '@idraw/types';
2
+ export declare function deepResizeGroupElement(elem: Element<'group'>, size: Pick<Partial<ElementSize>, 'w' | 'h'>): Element<'group'>;
@@ -0,0 +1,101 @@
1
+ import { formatNumber } from './number';
2
+ const doNum = (n) => {
3
+ return formatNumber(n, { decimalPlaces: 4 });
4
+ };
5
+ function resizeElementBaseDetail(elem, opts) {
6
+ const { detail } = elem;
7
+ const { xRatio, yRatio, maxRatio } = opts;
8
+ const middleRatio = (xRatio + yRatio) / 2;
9
+ const { borderWidth, borderRadius, borderDash, shadowOffsetX, shadowOffsetY, shadowBlur } = detail;
10
+ if (typeof borderWidth === 'number') {
11
+ detail.borderWidth = doNum(borderWidth * middleRatio);
12
+ }
13
+ else if (Array.isArray(detail.borderWidth)) {
14
+ const bw = borderWidth;
15
+ detail.borderWidth = [doNum(bw[0] * yRatio), doNum(bw[1] * xRatio), doNum(bw[2] * yRatio), doNum(bw[3] * xRatio)];
16
+ }
17
+ if (typeof borderRadius === 'number') {
18
+ detail.borderRadius = doNum(borderRadius * middleRatio);
19
+ }
20
+ else if (Array.isArray(detail.borderRadius)) {
21
+ const br = borderRadius;
22
+ detail.borderRadius = [br[0] * xRatio, br[1] * xRatio, br[2] * yRatio, br[3] * yRatio];
23
+ }
24
+ if (Array.isArray(borderDash)) {
25
+ borderDash.forEach((dash, i) => {
26
+ detail.borderDash[i] = doNum(dash * maxRatio);
27
+ });
28
+ }
29
+ if (typeof shadowOffsetX === 'number') {
30
+ detail.shadowOffsetX = doNum(shadowOffsetX * maxRatio);
31
+ }
32
+ if (typeof shadowOffsetY === 'number') {
33
+ detail.shadowOffsetX = doNum(shadowOffsetY * maxRatio);
34
+ }
35
+ if (typeof shadowBlur === 'number') {
36
+ detail.shadowOffsetX = doNum(shadowBlur * maxRatio);
37
+ }
38
+ }
39
+ function resizeElementBase(elem, opts) {
40
+ const { xRatio, yRatio } = opts;
41
+ const { x, y, w, h } = elem;
42
+ elem.x = doNum(x * xRatio);
43
+ elem.y = doNum(y * yRatio);
44
+ elem.w = doNum(w * xRatio);
45
+ elem.h = doNum(h * yRatio);
46
+ resizeElementBaseDetail(elem, opts);
47
+ }
48
+ function resizeTextElementDetail(elem, opts) {
49
+ const { minRatio, maxRatio } = opts;
50
+ const { fontSize, lineHeight } = elem.detail;
51
+ const ratio = (minRatio + maxRatio) / 2;
52
+ if (fontSize && fontSize > 0) {
53
+ elem.detail.fontSize = doNum(fontSize * ratio);
54
+ }
55
+ if (lineHeight && lineHeight > 0) {
56
+ elem.detail.lineHeight = doNum(lineHeight * ratio);
57
+ }
58
+ }
59
+ function resizeElement(elem, opts) {
60
+ const { type } = elem;
61
+ resizeElementBase(elem, opts);
62
+ if (type === 'circle') {
63
+ }
64
+ else if (type === 'text') {
65
+ resizeTextElementDetail(elem, opts);
66
+ }
67
+ else if (type === 'image') {
68
+ }
69
+ else if (type === 'svg') {
70
+ }
71
+ else if (type === 'html') {
72
+ }
73
+ else if (type === 'path') {
74
+ }
75
+ else if (type === 'group' && Array.isArray(elem.detail.children)) {
76
+ elem.detail.children.forEach((child) => {
77
+ resizeElement(child, opts);
78
+ });
79
+ }
80
+ }
81
+ export function deepResizeGroupElement(elem, size) {
82
+ const resizeW = size.w && size.w > 0 ? size.w : elem.w;
83
+ const resizeH = size.h && size.h > 0 ? size.h : elem.h;
84
+ const xRatio = resizeW / elem.w;
85
+ const yRatio = resizeH / elem.h;
86
+ if (xRatio === yRatio && xRatio === 1) {
87
+ return elem;
88
+ }
89
+ const minRatio = Math.min(xRatio, yRatio);
90
+ const maxRatio = Math.max(xRatio, yRatio);
91
+ elem.w = resizeW;
92
+ elem.h = resizeH;
93
+ const opts = { xRatio, yRatio, minRatio, maxRatio };
94
+ if (elem.type === 'group' && Array.isArray(elem.detail.children)) {
95
+ elem.detail.children.forEach((child) => {
96
+ resizeElement(child, opts);
97
+ });
98
+ }
99
+ resizeElementBaseDetail(elem, opts);
100
+ return elem;
101
+ }
@@ -1,6 +1,5 @@
1
- export declare class Store<T extends Record<string | symbol, any>> {
2
- private _temp;
3
- private _backUpDefaultStorage;
1
+ export declare class Store<T extends Record<string | symbol, any> = Record<string | symbol, any>> {
2
+ #private;
4
3
  constructor(opts: {
5
4
  defaultStorage: T;
6
5
  });
@@ -8,5 +7,5 @@ export declare class Store<T extends Record<string | symbol, any>> {
8
7
  get<K extends keyof T>(name: K): T[K];
9
8
  getSnapshot(): T;
10
9
  clear(): void;
11
- private _createTempStorage;
10
+ destroy(): void;
12
11
  }
@@ -1,22 +1,40 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _Store_instances, _Store_temp, _Store_backUpDefaultStorage, _Store_createTempStorage;
1
13
  import { deepClone } from './data';
2
14
  export class Store {
3
15
  constructor(opts) {
4
- this._backUpDefaultStorage = deepClone(opts.defaultStorage);
5
- this._temp = this._createTempStorage();
16
+ _Store_instances.add(this);
17
+ _Store_temp.set(this, void 0);
18
+ _Store_backUpDefaultStorage.set(this, void 0);
19
+ __classPrivateFieldSet(this, _Store_backUpDefaultStorage, deepClone(opts.defaultStorage), "f");
20
+ __classPrivateFieldSet(this, _Store_temp, __classPrivateFieldGet(this, _Store_instances, "m", _Store_createTempStorage).call(this), "f");
6
21
  }
7
22
  set(name, value) {
8
- this._temp[name] = value;
23
+ __classPrivateFieldGet(this, _Store_temp, "f")[name] = value;
9
24
  }
10
25
  get(name) {
11
- return this._temp[name];
26
+ return __classPrivateFieldGet(this, _Store_temp, "f")[name];
12
27
  }
13
28
  getSnapshot() {
14
- return deepClone(this._temp);
29
+ return deepClone(__classPrivateFieldGet(this, _Store_temp, "f"));
15
30
  }
16
31
  clear() {
17
- this._temp = this._createTempStorage();
32
+ __classPrivateFieldSet(this, _Store_temp, __classPrivateFieldGet(this, _Store_instances, "m", _Store_createTempStorage).call(this), "f");
18
33
  }
19
- _createTempStorage() {
20
- return deepClone(this._backUpDefaultStorage);
34
+ destroy() {
35
+ __classPrivateFieldSet(this, _Store_temp, null, "f");
21
36
  }
22
37
  }
38
+ _Store_temp = new WeakMap(), _Store_backUpDefaultStorage = new WeakMap(), _Store_instances = new WeakSet(), _Store_createTempStorage = function _Store_createTempStorage() {
39
+ return deepClone(__classPrivateFieldGet(this, _Store_backUpDefaultStorage, "f"));
40
+ };
@@ -2,4 +2,5 @@ type Middleware = (ctx: any, next: Middleware) => any;
2
2
  export declare function compose(middleware: Middleware[]): (context: any, next?: Middleware) => any;
3
3
  export declare function delay(time: number): Promise<void>;
4
4
  export declare function throttle(fn: (...args: any[]) => any, timeout: number): (...args: any[]) => any;
5
+ export declare function debounce(fn: (...args: any[]) => any, timeout: number): (...args: any[]) => any;
5
6
  export {};
@@ -27,7 +27,7 @@ export function delay(time) {
27
27
  export function throttle(fn, timeout) {
28
28
  let timer = -1;
29
29
  return function (...args) {
30
- if (timer > 0) {
30
+ if (timer >= 0) {
31
31
  return;
32
32
  }
33
33
  timer = setTimeout(() => {
@@ -36,3 +36,15 @@ export function throttle(fn, timeout) {
36
36
  }, timeout);
37
37
  };
38
38
  }
39
+ export function debounce(fn, timeout) {
40
+ let timer = -1;
41
+ return function (...args) {
42
+ if (timer >= 0) {
43
+ window.clearTimeout(timer);
44
+ }
45
+ timer = setTimeout(() => {
46
+ fn(...args);
47
+ timer = -1;
48
+ }, timeout);
49
+ };
50
+ }
@@ -3,8 +3,9 @@ const defaultElemConfig = getDefaultElementDetailConfig();
3
3
  export function calcViewBoxSize(viewElem, opts) {
4
4
  const { viewScaleInfo } = opts;
5
5
  const { scale } = viewScaleInfo;
6
- let { borderRadius, boxSizing = defaultElemConfig.boxSizing, borderWidth } = viewElem.detail;
7
- if (typeof borderWidth !== 'number') {
6
+ let { borderRadius } = viewElem.detail;
7
+ const { boxSizing = defaultElemConfig.boxSizing, borderWidth } = viewElem.detail;
8
+ if (Array.isArray(borderWidth)) {
8
9
  borderRadius = 0;
9
10
  }
10
11
  let { x, y, w, h } = viewElem;
@@ -0,0 +1,10 @@
1
+ import type { Data, ViewSizeInfo } from 'idraw';
2
+ interface ViewCenterContentResult {
3
+ offsetX: number;
4
+ offsetY: number;
5
+ scale: number;
6
+ }
7
+ export declare function calcViewCenterContent(data: Data, opts: {
8
+ viewSizeInfo: ViewSizeInfo;
9
+ }): ViewCenterContentResult;
10
+ export {};
@@ -0,0 +1,53 @@
1
+ import { rotateElementVertexes } from './rotate';
2
+ import { formatNumber } from './number';
3
+ export function calcViewCenterContent(data, opts) {
4
+ let offsetX = 0;
5
+ let offsetY = 0;
6
+ let scale = 0;
7
+ let contentX = 0;
8
+ let contentY = 0;
9
+ let contentW = 0;
10
+ let contentH = 0;
11
+ const { width, height } = opts.viewSizeInfo;
12
+ data.elements.forEach((elem) => {
13
+ const elemSize = {
14
+ x: elem.x,
15
+ y: elem.y,
16
+ w: elem.w,
17
+ h: elem.h,
18
+ angle: elem.angle
19
+ };
20
+ if (elemSize.angle && (elemSize.angle > 0 || elemSize.angle < 0)) {
21
+ const ves = rotateElementVertexes(elemSize);
22
+ if (ves.length === 4) {
23
+ const xList = [ves[0].x, ves[1].x, ves[2].x, ves[3].x];
24
+ const yList = [ves[0].y, ves[1].y, ves[2].y, ves[3].y];
25
+ elemSize.x = Math.min(...xList);
26
+ elemSize.y = Math.min(...yList);
27
+ elemSize.w = Math.abs(Math.max(...xList) - Math.min(...xList));
28
+ elemSize.h = Math.abs(Math.max(...yList) - Math.min(...yList));
29
+ }
30
+ }
31
+ const areaStartX = Math.min(elemSize.x, contentX);
32
+ const areaStartY = Math.min(elemSize.y, contentY);
33
+ const areaEndX = Math.max(elemSize.x + elemSize.w, contentX + contentW);
34
+ const areaEndY = Math.max(elemSize.y + elemSize.h, contentY + contentH);
35
+ contentX = areaStartX;
36
+ contentY = areaStartY;
37
+ contentW = Math.abs(areaEndX - areaStartX);
38
+ contentH = Math.abs(areaEndY - areaStartY);
39
+ });
40
+ if (contentW > 0 && contentH > 0) {
41
+ const scaleW = formatNumber(width / contentW, { decimalPlaces: 4 });
42
+ const scaleH = formatNumber(height / contentH, { decimalPlaces: 4 });
43
+ scale = Math.min(scaleW, scaleH, 1);
44
+ offsetX = (contentW * scale - width) / 2 / scale;
45
+ offsetY = (contentH * scale - height) / 2 / scale;
46
+ }
47
+ const result = {
48
+ offsetX: formatNumber(offsetX, { decimalPlaces: 0 }),
49
+ offsetY: formatNumber(offsetY, { decimalPlaces: 0 }),
50
+ scale
51
+ };
52
+ return result;
53
+ }