@douyinfe/semi-foundation 2.72.2 → 2.73.0-beta.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 (60) hide show
  1. package/audioPlayer/audioPlayer.scss +217 -0
  2. package/audioPlayer/constants.ts +7 -0
  3. package/audioPlayer/foundation.ts +103 -0
  4. package/audioPlayer/variables.scss +55 -0
  5. package/button/iconButton.scss +8 -0
  6. package/cropper/constants.ts +26 -0
  7. package/cropper/cropper.scss +116 -0
  8. package/cropper/foundation.ts +821 -0
  9. package/cropper/utils.ts +12 -0
  10. package/cropper/variables.scss +6 -0
  11. package/dragMove/foundation.ts +12 -0
  12. package/jsonViewer/foundation.ts +6 -0
  13. package/jsonViewer/jsonViewer.scss +8 -3
  14. package/lib/cjs/audioPlayer/audioPlayer.css +188 -0
  15. package/lib/cjs/audioPlayer/audioPlayer.scss +217 -0
  16. package/lib/cjs/audioPlayer/constants.d.ts +4 -0
  17. package/lib/cjs/audioPlayer/constants.js +10 -0
  18. package/lib/cjs/audioPlayer/foundation.d.ts +41 -0
  19. package/lib/cjs/audioPlayer/foundation.js +79 -0
  20. package/lib/cjs/audioPlayer/variables.scss +55 -0
  21. package/lib/cjs/button/iconButton.css +8 -0
  22. package/lib/cjs/button/iconButton.scss +8 -0
  23. package/lib/cjs/cropper/constants.d.ts +17 -0
  24. package/lib/cjs/cropper/constants.js +24 -0
  25. package/lib/cjs/cropper/cropper.css +97 -0
  26. package/lib/cjs/cropper/cropper.scss +116 -0
  27. package/lib/cjs/cropper/foundation.d.ts +101 -0
  28. package/lib/cjs/cropper/foundation.js +786 -0
  29. package/lib/cjs/cropper/utils.d.ts +2 -0
  30. package/lib/cjs/cropper/utils.js +19 -0
  31. package/lib/cjs/cropper/variables.scss +6 -0
  32. package/lib/cjs/dragMove/foundation.d.ts +2 -0
  33. package/lib/cjs/dragMove/foundation.js +10 -0
  34. package/lib/cjs/jsonViewer/foundation.js +6 -0
  35. package/lib/cjs/jsonViewer/jsonViewer.css +8 -2
  36. package/lib/cjs/jsonViewer/jsonViewer.scss +8 -3
  37. package/lib/es/audioPlayer/audioPlayer.css +188 -0
  38. package/lib/es/audioPlayer/audioPlayer.scss +217 -0
  39. package/lib/es/audioPlayer/constants.d.ts +4 -0
  40. package/lib/es/audioPlayer/constants.js +5 -0
  41. package/lib/es/audioPlayer/foundation.d.ts +41 -0
  42. package/lib/es/audioPlayer/foundation.js +72 -0
  43. package/lib/es/audioPlayer/variables.scss +55 -0
  44. package/lib/es/button/iconButton.css +8 -0
  45. package/lib/es/button/iconButton.scss +8 -0
  46. package/lib/es/cropper/constants.d.ts +17 -0
  47. package/lib/es/cropper/constants.js +19 -0
  48. package/lib/es/cropper/cropper.css +97 -0
  49. package/lib/es/cropper/cropper.scss +116 -0
  50. package/lib/es/cropper/foundation.d.ts +101 -0
  51. package/lib/es/cropper/foundation.js +778 -0
  52. package/lib/es/cropper/utils.d.ts +2 -0
  53. package/lib/es/cropper/utils.js +12 -0
  54. package/lib/es/cropper/variables.scss +6 -0
  55. package/lib/es/dragMove/foundation.d.ts +2 -0
  56. package/lib/es/dragMove/foundation.js +10 -0
  57. package/lib/es/jsonViewer/foundation.js +6 -0
  58. package/lib/es/jsonViewer/jsonViewer.css +8 -2
  59. package/lib/es/jsonViewer/jsonViewer.scss +8 -3
  60. package/package.json +4 -4
@@ -0,0 +1,778 @@
1
+ import BaseFoundation from "../base/foundation";
2
+ import { getMiddle, getAspectHW } from "./utils";
3
+ export default class CropperFoundation extends BaseFoundation {
4
+ constructor(adapter) {
5
+ super(Object.assign({}, adapter));
6
+ this.getImgDataWhenResize = ratio => {
7
+ const {
8
+ imgData
9
+ } = this.getStates();
10
+ const newImgData = {
11
+ width: imgData.width * ratio,
12
+ height: imgData.height * ratio,
13
+ centerPoint: {
14
+ x: imgData.centerPoint.x * ratio,
15
+ y: imgData.centerPoint.y * ratio
16
+ }
17
+ };
18
+ this.imgData.scale *= ratio;
19
+ return newImgData;
20
+ };
21
+ this.getCropperBoxWhenResize = (ratio, newContainerData) => {
22
+ const {
23
+ cropperBox
24
+ } = this.getStates();
25
+ const {
26
+ aspectRatio
27
+ } = this.getProps();
28
+ const tempCropperBox = {
29
+ width: cropperBox.width * ratio,
30
+ height: cropperBox.height * ratio,
31
+ centerPoint: {
32
+ x: cropperBox.centerPoint.x * ratio,
33
+ y: cropperBox.centerPoint.y * ratio
34
+ }
35
+ };
36
+ let xMin = tempCropperBox.centerPoint.x - tempCropperBox.width / 2;
37
+ let xMax = tempCropperBox.centerPoint.x + tempCropperBox.width / 2;
38
+ let yMin = tempCropperBox.centerPoint.y - tempCropperBox.height / 2;
39
+ let yMax = tempCropperBox.centerPoint.y + tempCropperBox.height / 2;
40
+ if (aspectRatio) {
41
+ if (xMax > newContainerData.width) {
42
+ xMax = newContainerData.width;
43
+ xMin = tempCropperBox.width > newContainerData.width ? 0 : newContainerData.width - tempCropperBox.width;
44
+ tempCropperBox.width = xMax - xMin;
45
+ tempCropperBox.height = tempCropperBox.width / aspectRatio;
46
+ yMax = yMin + tempCropperBox.height;
47
+ }
48
+ if (yMax > newContainerData.height) {
49
+ yMax = newContainerData.height;
50
+ yMin = tempCropperBox.height > newContainerData.height ? 0 : newContainerData.height - tempCropperBox.height;
51
+ tempCropperBox.height = yMax - yMin;
52
+ tempCropperBox.width = tempCropperBox.height * aspectRatio;
53
+ xMax = xMin + tempCropperBox.width;
54
+ }
55
+ } else {
56
+ if (xMax > newContainerData.width) {
57
+ xMax = newContainerData.width;
58
+ xMin = tempCropperBox.width > newContainerData.width ? 0 : newContainerData.width - tempCropperBox.width;
59
+ }
60
+ if (yMax > newContainerData.height) {
61
+ yMax = newContainerData.height;
62
+ yMin = tempCropperBox.height > newContainerData.height ? 0 : newContainerData.height - tempCropperBox.height;
63
+ }
64
+ }
65
+ return {
66
+ width: xMax - xMin,
67
+ height: yMax - yMin,
68
+ centerPoint: {
69
+ x: (xMax + xMin) / 2,
70
+ y: (yMax + yMin) / 2
71
+ }
72
+ };
73
+ };
74
+ this.handleResize = () => {
75
+ const {
76
+ loaded
77
+ } = this.getStates();
78
+ if (!this.initial) {
79
+ this.initial = true;
80
+ return;
81
+ }
82
+ if (!loaded) {
83
+ return;
84
+ }
85
+ const container = this._adapter.getContainer();
86
+ const newContainerData = {
87
+ width: container.clientWidth,
88
+ height: container.clientHeight
89
+ };
90
+ const ratio = newContainerData.width / this.containerData.width;
91
+ const newImgData = this.getImgDataWhenResize(ratio);
92
+ const newCropperBox = this.getCropperBoxWhenResize(ratio, newContainerData);
93
+ this.containerData = newContainerData;
94
+ this.setState({
95
+ imgData: newImgData,
96
+ cropperBox: newCropperBox
97
+ });
98
+ };
99
+ this.handleImageLoad = e => {
100
+ /**
101
+ * 1. 图片加载完成后,获得图片的原始大小
102
+ * 2. 计算图片的缩放比例,中心点位置
103
+ */
104
+ const {
105
+ naturalWidth,
106
+ naturalHeight
107
+ } = e.target;
108
+ const {
109
+ width: containerWidth,
110
+ height: containerHeight
111
+ } = this.containerData;
112
+ this.imgData.originalWidth = naturalWidth;
113
+ this.imgData.originalHeight = naturalHeight;
114
+ let scale = 1;
115
+ const newImgDataState = {};
116
+ /* 计算图片加载后的初始显示尺寸 */
117
+ if (naturalWidth / containerWidth > naturalHeight / containerHeight) {
118
+ scale = containerWidth / naturalWidth;
119
+ newImgDataState.width = containerWidth;
120
+ newImgDataState.height = naturalHeight * scale;
121
+ } else {
122
+ scale = containerHeight / naturalHeight;
123
+ newImgDataState.width = naturalWidth * scale;
124
+ newImgDataState.height = containerHeight;
125
+ }
126
+ this.imgData.scale = scale;
127
+ newImgDataState.centerPoint = {};
128
+ newImgDataState.centerPoint.x = containerWidth / 2;
129
+ newImgDataState.centerPoint.y = containerHeight / 2;
130
+ /* 计算裁切框大小 */
131
+ const newCropperBoxState = {};
132
+ const {
133
+ defaultAspectRatio,
134
+ aspectRatio
135
+ } = this.getProps();
136
+ const calcAspect = aspectRatio || defaultAspectRatio;
137
+ if (containerWidth / containerHeight > calcAspect) {
138
+ newCropperBoxState.width = containerHeight * calcAspect;
139
+ newCropperBoxState.height = containerHeight;
140
+ } else {
141
+ newCropperBoxState.width = containerWidth;
142
+ newCropperBoxState.height = containerWidth / calcAspect;
143
+ }
144
+ newCropperBoxState.centerPoint = {};
145
+ newCropperBoxState.centerPoint.x = containerWidth / 2;
146
+ newCropperBoxState.centerPoint.y = containerHeight / 2;
147
+ this.setState({
148
+ imgData: newImgDataState,
149
+ cropperBox: newCropperBoxState,
150
+ loaded: true
151
+ });
152
+ };
153
+ this.handleWheel = e => {
154
+ // 防止双手缩放导致页面被放大
155
+ e.preventDefault();
156
+ const {
157
+ imgData,
158
+ zoom: currZoom
159
+ } = this.getStates();
160
+ const {
161
+ maxZoom,
162
+ minZoom,
163
+ zoomStep
164
+ } = this.getProps();
165
+ let _zoom;
166
+ if (e.deltaY < 0) {
167
+ /* zoom in */
168
+ if (currZoom + zoomStep <= maxZoom) {
169
+ _zoom = Number((currZoom + zoomStep).toFixed(2));
170
+ }
171
+ } else if (e.deltaY > 0) {
172
+ /* zoom out */
173
+ if (currZoom - zoomStep >= minZoom) {
174
+ _zoom = Number((currZoom - zoomStep).toFixed(2));
175
+ }
176
+ }
177
+ if (_zoom === undefined) {
178
+ return;
179
+ }
180
+ const boundingRect = e.currentTarget.getBoundingClientRect();
181
+ const offsetX = e.clientX - boundingRect.left;
182
+ const offsetY = e.clientY - boundingRect.top;
183
+ const scaleCenter = {
184
+ x: offsetX,
185
+ y: -offsetY
186
+ };
187
+ // 计算新的中心点位置
188
+ const currentPoint = Object.assign({}, imgData.centerPoint);
189
+ currentPoint.y = -currentPoint.y;
190
+ const newCenterPoint = {
191
+ x: (currentPoint.x - scaleCenter.x) / currZoom * _zoom + scaleCenter.x,
192
+ y: -[(currentPoint.y - scaleCenter.y) / currZoom * _zoom + scaleCenter.y]
193
+ };
194
+ const newWidth = imgData.width / currZoom * _zoom;
195
+ const newHeight = imgData.height / currZoom * _zoom;
196
+ const newImgDataState = {
197
+ width: newWidth,
198
+ height: newHeight,
199
+ centerPoint: newCenterPoint
200
+ };
201
+ this.setState({
202
+ imgData: newImgDataState,
203
+ zoom: _zoom
204
+ });
205
+ this._adapter.notifyZoomChange(_zoom);
206
+ };
207
+ this.getRangeForAspectChange = () => {
208
+ const {
209
+ cropperBox
210
+ } = this.getStates();
211
+ const {
212
+ aspectRatio
213
+ } = this.getProps();
214
+ const {
215
+ width: containerWidth,
216
+ height: containerHeight
217
+ } = this.containerData;
218
+ // 可能的最大宽高
219
+ let height, width;
220
+ // 裁剪框当前的位置
221
+ const xMin = cropperBox.centerPoint.x - cropperBox.width / 2;
222
+ const xMax = cropperBox.centerPoint.x + cropperBox.width / 2;
223
+ const yMin = cropperBox.centerPoint.y - cropperBox.height / 2;
224
+ const yMax = cropperBox.centerPoint.y + cropperBox.height / 2;
225
+ switch (this.boxMoveDir) {
226
+ case 'tl':
227
+ height = yMax;
228
+ width = xMax;
229
+ [width, height] = getAspectHW(width, height, aspectRatio);
230
+ this.rangeX = [xMax - width, xMax];
231
+ this.rangeY = [yMax - height, yMax];
232
+ break;
233
+ case 'tm':
234
+ height = yMax;
235
+ const leftHalfWidth = cropperBox.centerPoint.x;
236
+ const rightHalfWidth = containerWidth - cropperBox.centerPoint.x;
237
+ width = 2 * (leftHalfWidth < rightHalfWidth ? leftHalfWidth : rightHalfWidth);
238
+ [width, height] = getAspectHW(width, height, aspectRatio);
239
+ this.rangeX = [cropperBox.centerPoint.x - width / 2, cropperBox.centerPoint.x + width / 2];
240
+ this.rangeY = [yMax - height, yMax];
241
+ break;
242
+ case 'tr':
243
+ height = yMax;
244
+ width = containerWidth - xMin;
245
+ [width, height] = getAspectHW(width, height, aspectRatio);
246
+ this.rangeX = [xMin, xMin + width];
247
+ this.rangeY = [yMax - height, yMax];
248
+ break;
249
+ case 'ml':
250
+ width = xMax;
251
+ const topHalfHeight = cropperBox.centerPoint.y;
252
+ const bottomHalfHeight = containerHeight - cropperBox.centerPoint.y;
253
+ height = 2 * (topHalfHeight < bottomHalfHeight ? topHalfHeight : bottomHalfHeight);
254
+ [width, height] = getAspectHW(width, height, aspectRatio);
255
+ this.rangeX = [xMax - width, xMax];
256
+ this.rangeY = [cropperBox.centerPoint.y - height / 2, cropperBox.centerPoint.y + height / 2];
257
+ break;
258
+ case 'mr':
259
+ width = containerWidth - xMin;
260
+ const topHalfHeight2 = cropperBox.centerPoint.y;
261
+ const bottomHalfHeight2 = containerHeight - cropperBox.centerPoint.y;
262
+ height = 2 * (topHalfHeight2 < bottomHalfHeight2 ? topHalfHeight2 : bottomHalfHeight2);
263
+ [width, height] = getAspectHW(width, height, aspectRatio);
264
+ this.rangeX = [xMin, xMin + width];
265
+ this.rangeY = [cropperBox.centerPoint.y - height / 2, cropperBox.centerPoint.y + height / 2];
266
+ break;
267
+ case 'bl':
268
+ height = containerHeight - yMin;
269
+ width = xMax;
270
+ [width, height] = getAspectHW(width, height, aspectRatio);
271
+ this.rangeX = [xMax - width, xMax];
272
+ this.rangeY = [yMin, yMin + height];
273
+ break;
274
+ case 'bm':
275
+ height = containerHeight - yMin;
276
+ const leftHalfWidth2 = cropperBox.centerPoint.x;
277
+ const rightHalfWidth2 = containerWidth - cropperBox.centerPoint.x;
278
+ width = 2 * (leftHalfWidth2 < rightHalfWidth2 ? leftHalfWidth2 : rightHalfWidth2);
279
+ [width, height] = getAspectHW(width, height, aspectRatio);
280
+ this.rangeX = [cropperBox.centerPoint.x - width / 2, cropperBox.centerPoint.x + width / 2];
281
+ this.rangeY = [yMin, yMin + height];
282
+ break;
283
+ case 'br':
284
+ height = containerHeight - yMin;
285
+ width = containerWidth - xMin;
286
+ [width, height] = getAspectHW(width, height, aspectRatio);
287
+ this.rangeX = [xMin, xMin + width];
288
+ this.rangeY = [yMin, yMin + height];
289
+ break;
290
+ default:
291
+ break;
292
+ }
293
+ };
294
+ this.handleCornerMouseDown = e => {
295
+ const currentTarget = e.currentTarget;
296
+ if (!currentTarget) {
297
+ return;
298
+ }
299
+ e.preventDefault();
300
+ const dir = currentTarget.dataset.dir;
301
+ this.boxMoveDir = dir;
302
+ this.boxMoveParam = this.getMoveParamByDir(dir);
303
+ this.bindResizeEvent();
304
+ const {
305
+ aspectRatio
306
+ } = this.getProps();
307
+ if (aspectRatio) {
308
+ this.getRangeForAspectChange();
309
+ } else {
310
+ this.rangeX = [0, this.containerData.width];
311
+ this.rangeY = [0, this.containerData.height];
312
+ }
313
+ };
314
+ this.bindResizeEvent = () => {
315
+ const {
316
+ aspectRatio
317
+ } = this.getProps();
318
+ document.addEventListener('mousemove', aspectRatio ? this.handleCornerAspectMouseMove : this.handleCornerMouseMove);
319
+ document.addEventListener('mouseup', this.handleCornerMouseUp);
320
+ };
321
+ this.unBindResizeEvent = () => {
322
+ const {
323
+ aspectRatio
324
+ } = this.getProps();
325
+ document.removeEventListener('mousemove', aspectRatio ? this.handleCornerAspectMouseMove : this.handleCornerMouseMove);
326
+ document.removeEventListener('mouseup', this.handleCornerMouseUp);
327
+ };
328
+ this.viewIMGDragStart = e => {
329
+ e.preventDefault();
330
+ };
331
+ this.handleCornerAspectMouseMove = e => {
332
+ e.preventDefault();
333
+ const {
334
+ clientX,
335
+ clientY
336
+ } = e;
337
+ const {
338
+ cropperBox
339
+ } = this.getStates();
340
+ const {
341
+ aspectRatio
342
+ } = this.getProps();
343
+ const boundingRect = this._adapter.getContainer().getBoundingClientRect();
344
+ const newCropperBoxPos = {
345
+ width: cropperBox.width,
346
+ height: cropperBox.height,
347
+ centerPoint: Object.assign({}, cropperBox.centerPoint)
348
+ };
349
+ let offsetX, offsetY;
350
+ if (['ml', 'mr'].includes(this.boxMoveDir)) {
351
+ offsetX = getMiddle(clientX - boundingRect.left, this.rangeX);
352
+ } else {
353
+ offsetY = getMiddle(clientY - boundingRect.top, this.rangeY);
354
+ }
355
+ switch (this.boxMoveDir) {
356
+ case 'tl':
357
+ newCropperBoxPos.height = this.rangeY[1] - offsetY;
358
+ newCropperBoxPos.width = newCropperBoxPos.height * aspectRatio;
359
+ newCropperBoxPos.centerPoint = {
360
+ x: this.rangeX[1] - newCropperBoxPos.width / 2,
361
+ y: this.rangeY[1] - newCropperBoxPos.height / 2
362
+ };
363
+ break;
364
+ case 'tm':
365
+ newCropperBoxPos.height = this.rangeY[1] - offsetY;
366
+ newCropperBoxPos.width = newCropperBoxPos.height * aspectRatio;
367
+ newCropperBoxPos.centerPoint = {
368
+ x: cropperBox.centerPoint.x,
369
+ y: this.rangeY[1] - newCropperBoxPos.height / 2
370
+ };
371
+ break;
372
+ case 'tr':
373
+ newCropperBoxPos.height = this.rangeY[1] - offsetY;
374
+ newCropperBoxPos.width = newCropperBoxPos.height * aspectRatio;
375
+ newCropperBoxPos.centerPoint = {
376
+ x: this.rangeX[0] + newCropperBoxPos.width / 2,
377
+ y: this.rangeY[1] - newCropperBoxPos.height / 2
378
+ };
379
+ break;
380
+ case 'ml':
381
+ newCropperBoxPos.width = this.rangeX[1] - offsetX;
382
+ newCropperBoxPos.height = newCropperBoxPos.width / aspectRatio;
383
+ newCropperBoxPos.centerPoint = {
384
+ x: this.rangeX[1] - newCropperBoxPos.width / 2,
385
+ y: cropperBox.centerPoint.y
386
+ };
387
+ break;
388
+ case 'mr':
389
+ newCropperBoxPos.width = offsetX - this.rangeX[0];
390
+ newCropperBoxPos.height = newCropperBoxPos.width / aspectRatio;
391
+ newCropperBoxPos.centerPoint = {
392
+ x: this.rangeX[0] + newCropperBoxPos.width / 2,
393
+ y: cropperBox.centerPoint.y
394
+ };
395
+ break;
396
+ case 'bl':
397
+ newCropperBoxPos.height = offsetY - this.rangeY[0];
398
+ newCropperBoxPos.width = newCropperBoxPos.height * aspectRatio;
399
+ newCropperBoxPos.centerPoint = {
400
+ x: this.rangeX[1] - newCropperBoxPos.width / 2,
401
+ y: this.rangeY[0] + newCropperBoxPos.height / 2
402
+ };
403
+ break;
404
+ case 'bm':
405
+ newCropperBoxPos.height = offsetY - this.rangeY[0];
406
+ newCropperBoxPos.width = newCropperBoxPos.height * aspectRatio;
407
+ newCropperBoxPos.centerPoint = {
408
+ x: cropperBox.centerPoint.x,
409
+ y: this.rangeY[0] + newCropperBoxPos.height / 2
410
+ };
411
+ break;
412
+ case 'br':
413
+ newCropperBoxPos.height = offsetY - this.rangeY[0];
414
+ newCropperBoxPos.width = newCropperBoxPos.height * aspectRatio;
415
+ newCropperBoxPos.centerPoint = {
416
+ x: this.rangeX[0] + newCropperBoxPos.width / 2,
417
+ y: this.rangeY[0] + newCropperBoxPos.height / 2
418
+ };
419
+ break;
420
+ default:
421
+ break;
422
+ }
423
+ if (newCropperBoxPos.height === 0 && newCropperBoxPos.width === 0) {
424
+ this.changeDir();
425
+ this.getRangeForAspectChange();
426
+ }
427
+ this.setState({
428
+ cropperBox: newCropperBoxPos
429
+ });
430
+ };
431
+ this.changeDir = () => {
432
+ if (this.boxMoveDir.includes('t')) {
433
+ this.boxMoveDir = this.boxMoveDir.replace('t', 'b');
434
+ } else if (this.boxMoveDir.includes('b')) {
435
+ this.boxMoveDir = this.boxMoveDir.replace('b', 't');
436
+ }
437
+ if (this.boxMoveDir.includes('l')) {
438
+ this.boxMoveDir = this.boxMoveDir.replace('l', 'r');
439
+ } else if (this.boxMoveDir.includes('r')) {
440
+ this.boxMoveDir = this.boxMoveDir.replace('r', 'l');
441
+ }
442
+ };
443
+ this.handleCornerMouseMove = e => {
444
+ e.preventDefault();
445
+ const {
446
+ clientX,
447
+ clientY
448
+ } = e;
449
+ const {
450
+ cropperBox
451
+ } = this.getStates();
452
+ const boundingRect = this._adapter.getContainer().getBoundingClientRect();
453
+ let offsetX = getMiddle(clientX - boundingRect.left, this.rangeX);
454
+ let offsetY = getMiddle(clientY - boundingRect.top, this.rangeY);
455
+ const newCropperBoxPos = {
456
+ width: cropperBox.width,
457
+ height: cropperBox.height,
458
+ centerPoint: {
459
+ x: cropperBox.centerPoint.x,
460
+ y: cropperBox.centerPoint.y
461
+ }
462
+ };
463
+ const {
464
+ paramX,
465
+ paramY
466
+ } = this.boxMoveParam;
467
+ let x, y;
468
+ if (paramX) {
469
+ x = cropperBox.centerPoint.x + paramX * cropperBox.width / 2;
470
+ newCropperBoxPos.width = cropperBox.width + paramX * (offsetX - x);
471
+ if (newCropperBoxPos.width < 0) {
472
+ newCropperBoxPos.width = -newCropperBoxPos.width;
473
+ this.boxMoveParam.paramX = -paramX;
474
+ }
475
+ newCropperBoxPos.centerPoint.x = offsetX - paramX * newCropperBoxPos.width / 2;
476
+ }
477
+ if (paramY) {
478
+ y = cropperBox.centerPoint.y + paramY * cropperBox.height / 2;
479
+ newCropperBoxPos.height = cropperBox.height + paramY * (offsetY - y);
480
+ if (newCropperBoxPos.height < 0) {
481
+ newCropperBoxPos.height = -newCropperBoxPos.height;
482
+ this.boxMoveParam.paramY = -paramY;
483
+ }
484
+ newCropperBoxPos.centerPoint.y = offsetY - paramY * newCropperBoxPos.height / 2;
485
+ }
486
+ this.setState({
487
+ cropperBox: newCropperBoxPos
488
+ });
489
+ };
490
+ this.handleCornerMouseUp = e => {
491
+ this.boxMoveParam = {
492
+ paramX: 0,
493
+ paramY: 0
494
+ };
495
+ this.unBindResizeEvent();
496
+ };
497
+ this.handleCropperBoxMouseDown = e => {
498
+ const target = e.target;
499
+ const {
500
+ cropperBox
501
+ } = this.getStates();
502
+ const container = this._adapter.getContainer();
503
+ const boundingRect = container.getBoundingClientRect();
504
+ if (target.dataset.dir) {
505
+ // 如果鼠标是落在了corner上,那么不做任何操作
506
+ return;
507
+ }
508
+ // 移动裁切框
509
+ this.cropperBoxMoveStart = {
510
+ x: e.clientX,
511
+ y: e.clientY
512
+ };
513
+ this.bindMoveEvent();
514
+ // 计算 cropperBox 中心点移动范围
515
+ this.moveRange = {
516
+ xMin: cropperBox.width / 2,
517
+ xMax: boundingRect.width - cropperBox.width / 2,
518
+ yMin: cropperBox.height / 2,
519
+ yMax: boundingRect.height - cropperBox.height / 2
520
+ };
521
+ };
522
+ this.bindMoveEvent = () => {
523
+ document.addEventListener('mousemove', this.handleCropperBoxMouseMove);
524
+ document.addEventListener('mouseup', this.handleCropperBoxMouseUp);
525
+ };
526
+ this.unBindMoveEvent = () => {
527
+ document.removeEventListener('mousemove', this.handleCropperBoxMouseMove);
528
+ document.removeEventListener('mouseup', this.handleCropperBoxMouseUp);
529
+ };
530
+ this.handleCropperBoxMouseMove = e => {
531
+ if (!this.cropperBoxMoveStart) {
532
+ return;
533
+ }
534
+ const {
535
+ clientX,
536
+ clientY
537
+ } = e;
538
+ const {
539
+ cropperBox
540
+ } = this.getStates();
541
+ const offsetX = clientX - this.cropperBoxMoveStart.x;
542
+ const offsetY = clientY - this.cropperBoxMoveStart.y;
543
+ const newCenterPointX = getMiddle(cropperBox.centerPoint.x + offsetX, [this.moveRange.xMin, this.moveRange.xMax]);
544
+ const newCenterPointY = getMiddle(cropperBox.centerPoint.y + offsetY, [this.moveRange.yMin, this.moveRange.yMax]);
545
+ const newCropperBoxPos = {
546
+ width: cropperBox.width,
547
+ height: cropperBox.height,
548
+ centerPoint: {
549
+ x: newCenterPointX,
550
+ y: newCenterPointY
551
+ }
552
+ };
553
+ this.cropperBoxMoveStart = {
554
+ x: clientX,
555
+ y: clientY
556
+ };
557
+ this.setState({
558
+ cropperBox: newCropperBoxPos
559
+ });
560
+ };
561
+ this.handleCropperBoxMouseUp = e => {
562
+ if (!this.cropperBoxMoveStart) {
563
+ return;
564
+ }
565
+ this.cropperBoxMoveStart = null;
566
+ this.unBindMoveEvent();
567
+ };
568
+ this.handleMaskMouseDown = e => {
569
+ if (e.currentTarget !== e.target) {
570
+ return;
571
+ }
572
+ this.bindImgMoveEvent();
573
+ // 记录开始移动的位置
574
+ this.imgMoveStart = {
575
+ x: e.clientX,
576
+ y: e.clientY
577
+ };
578
+ };
579
+ this.bindImgMoveEvent = () => {
580
+ document.addEventListener('mousemove', this.handleImgMove);
581
+ document.addEventListener('mouseup', this.handleImgMoveUp);
582
+ };
583
+ this.unBindImgMoveEvent = () => {
584
+ document.removeEventListener('mousemove', this.handleImgMove);
585
+ document.removeEventListener('mouseup', this.handleImgMoveUp);
586
+ };
587
+ this.handleImgMove = e => {
588
+ if (!this.imgMoveStart) {
589
+ return;
590
+ }
591
+ const {
592
+ clientX,
593
+ clientY
594
+ } = e;
595
+ const {
596
+ imgData
597
+ } = this.getStates();
598
+ const offsetX = clientX - this.imgMoveStart.x;
599
+ const offsetY = clientY - this.imgMoveStart.y;
600
+ const newCenterPointX = imgData.centerPoint.x + offsetX;
601
+ const newCenterPointY = imgData.centerPoint.y + offsetY;
602
+ const newImgData = {
603
+ width: imgData.width,
604
+ height: imgData.height,
605
+ centerPoint: {
606
+ x: newCenterPointX,
607
+ y: newCenterPointY
608
+ }
609
+ };
610
+ this.imgMoveStart = {
611
+ x: clientX,
612
+ y: clientY
613
+ };
614
+ this.setState({
615
+ imgData: newImgData
616
+ });
617
+ };
618
+ this.handleImgMoveUp = e => {
619
+ if (!this.imgMoveStart) {
620
+ return;
621
+ }
622
+ this.imgMoveStart = null;
623
+ this.unBindImgMoveEvent();
624
+ };
625
+ this.getCropperCanvas = () => {
626
+ const {
627
+ cropperBox,
628
+ imgData,
629
+ rotate,
630
+ zoom
631
+ } = this.getStates();
632
+ const {
633
+ fill
634
+ } = this.getProps();
635
+ const canvas = document.createElement('canvas');
636
+ const ctx = canvas.getContext('2d');
637
+ const img = this._adapter.getImg();
638
+ // 计算包含旋转后的图片的矩形容器的宽高
639
+ const angle = rotate * Math.PI / 180;
640
+ const sine = Math.abs(Math.sin(angle));
641
+ const cosine = Math.abs(Math.cos(angle));
642
+ const imgWidth = this.imgData.originalWidth;
643
+ const imgHeight = this.imgData.originalHeight;
644
+ const containerWidth = imgWidth * cosine + imgHeight * sine;
645
+ const containerHeight = imgHeight * cosine + imgWidth * sine;
646
+ // 判断裁切区域和外接矩形是否存在交集,如果不存在,则直接返回空白图片
647
+ // 计算需要裁剪的区域实际大小和位置
648
+ const cropperContainerWidth = containerWidth * zoom * this.imgData.scale;
649
+ const cropperContainerHeight = containerHeight * zoom * this.imgData.scale;
650
+ const cropperContainerTop = imgData.centerPoint.y - cropperContainerHeight / 2;
651
+ const cropperContainerLeft = imgData.centerPoint.x - cropperContainerWidth / 2;
652
+ const cropperBoxLeft = cropperBox.centerPoint.x - cropperBox.width / 2;
653
+ const cropperBoxTop = cropperBox.centerPoint.y - cropperBox.height / 2;
654
+ const realZoom = zoom * this.imgData.scale;
655
+ const relativeCropLeft = (cropperBoxLeft - cropperContainerLeft) / realZoom;
656
+ const relativeCropTop = (cropperBoxTop - cropperContainerTop) / realZoom;
657
+ const relativeWidth = cropperBox.width / realZoom;
658
+ const relativeHeight = cropperBox.height / realZoom;
659
+ const relativeCropRight = relativeCropLeft + relativeWidth;
660
+ const relativeCropBottom = relativeCropTop + relativeHeight;
661
+ if (relativeCropRight < 0 || relativeCropBottom < 0 || relativeCropLeft > containerWidth || relativeCropTop > containerHeight) {
662
+ // 没有交集,直接返回空白图片
663
+ const emptyCanvas = document.createElement('canvas');
664
+ const ctx = emptyCanvas.getContext('2d');
665
+ emptyCanvas.width = relativeWidth;
666
+ emptyCanvas.height = relativeHeight;
667
+ ctx.fillStyle = fill;
668
+ ctx.fillRect(0, 0, relativeWidth, relativeHeight);
669
+ return emptyCanvas;
670
+ }
671
+ canvas.width = containerWidth;
672
+ canvas.height = containerHeight;
673
+ ctx.fillStyle = fill;
674
+ ctx.fillRect(0, 0, containerWidth, containerHeight);
675
+ const halfWidth = containerWidth / 2;
676
+ const halfHeight = containerHeight / 2;
677
+ ctx.translate(halfWidth, halfHeight);
678
+ ctx.rotate(rotate * Math.PI / 180);
679
+ ctx.translate(-halfWidth, -halfHeight);
680
+ const imgX = (containerWidth - imgWidth) / 2;
681
+ const imgY = (containerHeight - imgHeight) / 2;
682
+ ctx.drawImage(img, 0, 0, imgWidth, imgHeight, imgX, imgY, imgWidth, imgHeight);
683
+ const canvas2 = document.createElement('canvas');
684
+ const ctx2 = canvas2.getContext('2d');
685
+ // 为了避免裁剪时候,超出被裁切的画布的部分颜色不正常,需要将裁切区域限制在画布范围内。
686
+ // 相对位置会在后续进行修正
687
+ let realLeft = relativeCropLeft;
688
+ let realTop = relativeCropTop;
689
+ let realWidth = relativeWidth;
690
+ let realHeight = relativeHeight;
691
+ if (relativeCropLeft < 0) {
692
+ realLeft = 0;
693
+ }
694
+ if (relativeCropTop < 0) {
695
+ realTop = 0;
696
+ }
697
+ if (relativeCropRight > containerWidth) {
698
+ realWidth = containerWidth - realLeft;
699
+ } else if (relativeCropLeft < 0) {
700
+ realWidth = relativeCropRight;
701
+ }
702
+ if (relativeCropBottom > containerHeight) {
703
+ realHeight = containerHeight - realTop;
704
+ } else if (relativeCropTop < 0) {
705
+ realHeight = relativeCropBottom;
706
+ }
707
+ const imgDataResult = ctx.getImageData(realLeft, realTop, realWidth, realHeight);
708
+ canvas2.width = relativeWidth;
709
+ canvas2.height = relativeHeight;
710
+ ctx2.fillStyle = fill;
711
+ ctx2.fillRect(0, 0, relativeWidth, relativeHeight);
712
+ ctx2.putImageData(imgDataResult, relativeCropLeft < 0 ? -relativeCropLeft : 0, relativeCropTop < 0 ? -relativeCropTop : 0);
713
+ return canvas2;
714
+ };
715
+ this.containerData = {};
716
+ this.imgData = {};
717
+ this.boxMoveDir = '';
718
+ this.boxMoveParam = {
719
+ paramX: 0,
720
+ paramY: 0
721
+ };
722
+ this.rangeX = null;
723
+ this.rangeY = null;
724
+ this.initial = false;
725
+ }
726
+ init() {
727
+ // 获取容器的宽高
728
+ // get cropping Container 's width & height
729
+ const container = this._adapter.getContainer();
730
+ this.containerData.width = container.clientWidth;
731
+ this.containerData.height = container.clientHeight;
732
+ this.cropperBoxMoveStart = null;
733
+ }
734
+ destroy() {
735
+ this.unBindMoveEvent();
736
+ this.unBindResizeEvent();
737
+ }
738
+ getMoveParamByDir(dir) {
739
+ let paramX = 0,
740
+ paramY = 0;
741
+ switch (dir) {
742
+ case 'tl':
743
+ paramX = -1;
744
+ paramY = -1;
745
+ break;
746
+ case 'tm':
747
+ paramY = -1;
748
+ break;
749
+ case 'tr':
750
+ paramX = 1;
751
+ paramY = -1;
752
+ break;
753
+ case 'ml':
754
+ paramX = -1;
755
+ break;
756
+ case 'mr':
757
+ paramX = 1;
758
+ break;
759
+ case 'bl':
760
+ paramX = -1;
761
+ paramY = 1;
762
+ break;
763
+ case 'bm':
764
+ paramY = 1;
765
+ break;
766
+ case 'br':
767
+ paramX = 1;
768
+ paramY = 1;
769
+ break;
770
+ default:
771
+ break;
772
+ }
773
+ return {
774
+ paramX,
775
+ paramY
776
+ };
777
+ }
778
+ }