hy-app 0.2.1 → 0.2.4

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 (78) hide show
  1. package/components/hy-button/index.scss +2 -0
  2. package/components/hy-cell/index.scss +0 -15
  3. package/components/hy-code-input/hy-code-input.vue +224 -0
  4. package/components/hy-code-input/index.scss +108 -0
  5. package/components/hy-code-input/props.ts +21 -0
  6. package/components/hy-code-input/typing.d.ts +65 -0
  7. package/components/hy-config-provider/hy-config-provider.vue +0 -1
  8. package/components/hy-config-provider/props.ts +1 -1
  9. package/components/hy-dropdown/props.ts +1 -1
  10. package/components/hy-dropdown-item/hy-dropdown-item.vue +2 -5
  11. package/components/hy-dropdown-item/index.scss +11 -13
  12. package/components/hy-grid/hy-grid.vue +7 -8
  13. package/components/hy-grid/props.ts +4 -0
  14. package/components/hy-grid/typing.d.ts +15 -0
  15. package/components/hy-icon/index.scss +2 -1
  16. package/components/hy-login/TheUserLogin.vue +0 -1
  17. package/components/hy-menu/hy-menu.vue +159 -0
  18. package/components/hy-menu/index.scss +58 -0
  19. package/components/hy-menu/props.ts +12 -0
  20. package/components/hy-menu/typing.d.ts +57 -0
  21. package/components/hy-modal/hy-modal.vue +5 -5
  22. package/components/hy-modal/index.scss +0 -6
  23. package/components/hy-notify/hy-notify.vue +169 -0
  24. package/components/hy-notify/index.scss +25 -0
  25. package/components/hy-notify/props.ts +14 -0
  26. package/components/hy-notify/typing.d.ts +44 -0
  27. package/components/hy-pagination/hy-pagination.vue +125 -0
  28. package/components/hy-pagination/index.scss +46 -0
  29. package/components/hy-pagination/props.ts +15 -0
  30. package/components/hy-pagination/typing.d.ts +44 -0
  31. package/components/hy-picker/index.scss +4 -0
  32. package/components/hy-scroll-list/index.scss +1 -1
  33. package/components/hy-search/index.scss +1 -2
  34. package/components/hy-signature/canvasHelper.ts +51 -0
  35. package/components/hy-signature/hy-signature.vue +656 -0
  36. package/components/hy-signature/index.scss +29 -0
  37. package/components/hy-signature/props.ts +29 -0
  38. package/components/hy-signature/typing.d.ts +181 -0
  39. package/components/hy-slider/index.scss +5 -1
  40. package/components/hy-subsection/hy-subsection.vue +15 -13
  41. package/components/hy-subsection/props.ts +2 -2
  42. package/components/hy-subsection/typing.d.ts +1 -1
  43. package/components/hy-swipe-action/hy-swipe-action.vue +288 -248
  44. package/components/hy-swipe-action/index.scss +34 -0
  45. package/components/hy-swipe-action/index.ts +34 -0
  46. package/components/hy-swipe-action/props.ts +15 -9
  47. package/components/hy-swipe-action/typing.d.ts +20 -22
  48. package/components/hy-swiper/index.scss +5 -0
  49. package/components/hy-tabBar/hy-tabBar.vue +96 -0
  50. package/components/hy-tabBar/index.scss +169 -0
  51. package/components/hy-tabBar/props.ts +13 -0
  52. package/components/hy-tabBar/typing.d.ts +54 -0
  53. package/components/hy-tabs/index.scss +2 -2
  54. package/components/hy-tag/index.scss +1 -1
  55. package/components/hy-text/index.scss +2 -2
  56. package/components/hy-textarea/hy-textarea.vue +5 -5
  57. package/components/hy-textarea/index.scss +5 -6
  58. package/components/hy-tooltip/index.scss +2 -2
  59. package/components/hy-upload/index.scss +1 -2
  60. package/components/hy-watermark/hy-watermark.vue +603 -0
  61. package/components/hy-watermark/index.scss +15 -0
  62. package/components/hy-watermark/props.ts +23 -0
  63. package/components/hy-watermark/typing.d.ts +76 -0
  64. package/components/index.ts +2 -2
  65. package/composables/index.ts +1 -0
  66. package/composables/useTouch.ts +48 -0
  67. package/index.ts +1 -1
  68. package/libs/css/mixin.scss +52 -13
  69. package/libs/css/vars.css +12 -2
  70. package/package.json +2 -2
  71. package/theme.scss +24 -46
  72. package/typing/modules/common.d.ts +1 -1
  73. package/utils/inspect.ts +20 -0
  74. package/utils/utils.ts +52 -22
  75. package/components/hy-swipe-action/index.wxs +0 -235
  76. package/components/hy-swipe-action/wxs.js +0 -15
  77. package/components/yk-tabbar/props.ts +0 -49
  78. package/components/yk-tabbar/yk-tabbar.vue +0 -224
@@ -0,0 +1,656 @@
1
+ <template>
2
+ <view class="hy-signature" :style="customStyle">
3
+ <view
4
+ class="hy-signature__content"
5
+ :style="{ borderRadius: addUnit(round) }"
6
+ >
7
+ <!-- #ifdef MP-WEIXIN -->
8
+ <canvas
9
+ class="hy-signature__content-canvas"
10
+ :style="canvasStyle"
11
+ :width="canvasState.canvasWidth"
12
+ :height="canvasState.canvasHeight"
13
+ :canvas-id="canvasId"
14
+ :id="canvasId"
15
+ :disable-scroll="disableScroll"
16
+ @touchstart="startDrawing"
17
+ @touchend="stopDrawing"
18
+ @touchmove="draw"
19
+ type="2d"
20
+ />
21
+ <!-- #endif -->
22
+ <!-- #ifndef MP-WEIXIN -->
23
+ <canvas
24
+ class="hy-signature__content-canvas"
25
+ :canvas-id="canvasId"
26
+ :style="canvasStyle"
27
+ :width="canvasState.canvasWidth"
28
+ :height="canvasState.canvasHeight"
29
+ :id="canvasId"
30
+ :disable-scroll="disableScroll"
31
+ @touchstart="startDrawing"
32
+ @touchend="stopDrawing"
33
+ @touchmove="draw"
34
+ />
35
+ <!-- #endif -->
36
+ </view>
37
+ <view class="hy-signature__footer">
38
+ <slot
39
+ name="footer"
40
+ :clear="clear"
41
+ :confirm="confirmSignature"
42
+ :current-step="currentStep"
43
+ :revoke="revoke"
44
+ :restore="restore"
45
+ :can-undo="lines.length > 0"
46
+ :can-redo="redoLines.length > 0"
47
+ :history-list="lines"
48
+ >
49
+ <block v-if="enableHistory">
50
+ <hy-button
51
+ size="small"
52
+ plain
53
+ shape="circle"
54
+ @click="revoke"
55
+ :disabled="lines.length <= 0"
56
+ :text="revokeText"
57
+ >
58
+ </hy-button>
59
+ <hy-button
60
+ size="small"
61
+ plain
62
+ shape="circle"
63
+ @click="restore"
64
+ :disabled="redoLines.length <= 0"
65
+ :text="restoreText"
66
+ ></hy-button>
67
+ </block>
68
+ <hy-button
69
+ size="small"
70
+ plain
71
+ shape="circle"
72
+ @click="clear"
73
+ :text="clearText"
74
+ ></hy-button>
75
+ <hy-button
76
+ size="small"
77
+ shape="circle"
78
+ @click="confirmSignature"
79
+ :text="confirmText"
80
+ ></hy-button>
81
+ </slot>
82
+ </view>
83
+ </view>
84
+ </template>
85
+ <script lang="ts">
86
+ export default {
87
+ name: "hy-signature",
88
+ options: {
89
+ addGlobalClass: true,
90
+ virtualHost: true,
91
+ styleIsolation: "shared",
92
+ },
93
+ };
94
+ </script>
95
+ <script lang="ts" setup>
96
+ import {
97
+ computed,
98
+ getCurrentInstance,
99
+ onBeforeMount,
100
+ onMounted,
101
+ reactive,
102
+ ref,
103
+ watch,
104
+ type CSSProperties,
105
+ } from "vue";
106
+ import { addUnit, getRect, guid } from "../../utils";
107
+ import type { SignatureExpose, SignatureResult, Point, Line } from "./typing";
108
+ import type IProps from "./typing";
109
+ import defaultProps from "./props";
110
+ // #ifdef MP-WEIXIN
111
+ import { canvas2dAdapter } from "./canvasHelper";
112
+ // #endif
113
+
114
+ // 组件
115
+ import HyButton from "@/package/components/hy-button/hy-button.vue";
116
+
117
+ const props = withDefaults(defineProps<IProps>(), defaultProps);
118
+ const emit = defineEmits(["start", "end", "signing", "confirm", "clear"]);
119
+ const instance = getCurrentInstance() as any;
120
+ const canvasId = ref<string>(`signature${guid()}`); // canvas 组件的唯一标识符
121
+ let canvas: null = null; //canvas对象 微信小程序生成图片必须传入
122
+ const drawing = ref<boolean>(false); // 是否正在绘制
123
+ const pixelRatio = ref<number>(1); // 像素比
124
+
125
+ const canvasState = reactive({
126
+ canvasWidth: 0,
127
+ canvasHeight: 0,
128
+ ctx: null as UniApp.CanvasContext | null, // canvas上下文
129
+ });
130
+
131
+ watch(
132
+ () => props.penColor,
133
+ () => {
134
+ setLine();
135
+ },
136
+ );
137
+
138
+ watch(
139
+ () => props.lineWidth,
140
+ () => {
141
+ setLine();
142
+ },
143
+ );
144
+
145
+ const canvasStyle = computed(() => {
146
+ const style: CSSProperties = {};
147
+ if (props.width) {
148
+ style.width = addUnit(props.width);
149
+ }
150
+
151
+ if (props.height) {
152
+ style.height = addUnit(props.height);
153
+ }
154
+
155
+ return `${style}`;
156
+ });
157
+
158
+ const disableScroll = computed(() => props.disableScroll);
159
+ const enableHistory = computed(() => props.enableHistory);
160
+
161
+ const lines = ref<Line[]>([]); // 保存所有线条
162
+ const redoLines = ref<Line[]>([]); // 保存撤销的线条
163
+ const currentLine = ref<Line>(); // 当前正在绘制的线
164
+ const currentStep = ref(0); // 当前步骤
165
+
166
+ /**
167
+ * @description 添加计算笔画宽度的方法
168
+ * */
169
+ function calculateLineWidth(speed: number): number {
170
+ if (!props.pressure) return props.lineWidth;
171
+
172
+ const minSpeed = props.minSpeed || 1.5;
173
+ const limitedSpeed = Math.min(minSpeed * 10, Math.max(minSpeed, speed));
174
+ const addWidth =
175
+ ((props.maxWidth - props.minWidth) * (limitedSpeed - minSpeed)) / minSpeed;
176
+ const lineWidth = Math.max(props.maxWidth - addWidth, props.minWidth);
177
+ return Math.min(lineWidth, props.maxWidth);
178
+ }
179
+
180
+ /**
181
+ * @description 获取默认笔画宽度
182
+ * */
183
+ const getDefaultLineWidth = () => {
184
+ if (props.pressure) {
185
+ // 在压感模式下,使用最大和最小宽度的平均值作为默认值
186
+ return (props.maxWidth + props.minWidth) / 2;
187
+ }
188
+ return props.lineWidth;
189
+ };
190
+
191
+ /**
192
+ * @description 开始画线
193
+ * */
194
+ const startDrawing = (e: any) => {
195
+ e.preventDefault();
196
+ drawing.value = true;
197
+ setLine();
198
+ emit("start", e);
199
+
200
+ // 创建新线条,同时保存当前的所有绘制参数
201
+ const { x, y } = e.touches[0];
202
+ currentLine.value = {
203
+ points: [
204
+ {
205
+ x,
206
+ y,
207
+ t: Date.now(), // 使用 t 替换 width
208
+ },
209
+ ],
210
+ color: props.penColor,
211
+ width: getDefaultLineWidth(),
212
+ backgroundColor: props.backgroundColor,
213
+ isPressure: props.pressure, // 添加笔锋模式标记
214
+ };
215
+
216
+ // 清空重做记录
217
+ redoLines.value = [];
218
+ draw(e);
219
+ };
220
+
221
+ /**
222
+ * @description 结束画线
223
+ * */
224
+ const stopDrawing = (e: TouchEvent) => {
225
+ e.preventDefault();
226
+ drawing.value = false;
227
+ if (currentLine.value) {
228
+ // 保存完整的线条信息,包括所有点的参数
229
+ lines.value.push({
230
+ ...currentLine.value,
231
+ points: currentLine.value.points.map((point) => ({
232
+ ...point,
233
+ t: point.t,
234
+ speed: point.speed,
235
+ distance: point.distance,
236
+ lineWidth: point.lineWidth,
237
+ lastX1: point.lastX1,
238
+ lastY1: point.lastY1,
239
+ lastX2: point.lastX2,
240
+ lastY2: point.lastY2,
241
+ isFirstPoint: point.isFirstPoint,
242
+ })),
243
+ });
244
+ currentStep.value = lines.value.length;
245
+ }
246
+ currentLine.value = undefined;
247
+ const { ctx } = canvasState;
248
+ if (ctx) ctx.beginPath();
249
+ emit("end", e);
250
+ };
251
+
252
+ /**
253
+ * @description 初始化 canvas
254
+ * @param forceUpdate 是否强制更新
255
+ */
256
+ const initCanvas = (forceUpdate: boolean = false) => {
257
+ // 如果不是强制更新,且已经初始化过 canvas,则不再重复初始化
258
+ if (!forceUpdate && canvasState.canvasHeight && canvasState.canvasWidth) {
259
+ return;
260
+ }
261
+ getContext().then(() => {
262
+ const { ctx } = canvasState;
263
+ if (ctx && props.backgroundColor) {
264
+ ctx.setFillStyle(props.backgroundColor);
265
+ ctx.fillRect(0, 0, canvasState.canvasWidth, canvasState.canvasHeight);
266
+ ctx.draw();
267
+ }
268
+ });
269
+ };
270
+
271
+ /**
272
+ * @description 清空 canvas
273
+ * */
274
+ const clear = () => {
275
+ lines.value = [];
276
+ redoLines.value = [];
277
+ currentStep.value = 0;
278
+ clearCanvas();
279
+ emit("clear");
280
+ };
281
+
282
+ // 确认签名
283
+ const confirmSignature = () => {
284
+ canvasToImage();
285
+ };
286
+
287
+ /**
288
+ * @description canvas划线
289
+ * */
290
+ const draw = (e: any) => {
291
+ e.preventDefault();
292
+ const { ctx } = canvasState;
293
+
294
+ if (!drawing.value || props.disabled || !ctx) return;
295
+ const { x, y } = e.touches[0];
296
+
297
+ const point: Point = {
298
+ x,
299
+ y,
300
+ t: Date.now(),
301
+ };
302
+
303
+ if (currentLine.value) {
304
+ const points = currentLine.value.points;
305
+ const prePoint = points[points.length - 1];
306
+
307
+ if (prePoint.t === point.t || (prePoint.x === x && prePoint.y === y)) {
308
+ return;
309
+ }
310
+
311
+ // 计算点的速度和距离
312
+ point.distance = Math.sqrt(
313
+ Math.pow(point.x - prePoint.x, 2) + Math.pow(point.y - prePoint.y, 2),
314
+ );
315
+ point.speed = point.distance / (point.t - prePoint.t || 0.1);
316
+
317
+ if (props.pressure) {
318
+ point.lineWidth = calculateLineWidth(point.speed);
319
+ // 处理线宽变化率限制
320
+ if (points.length >= 2) {
321
+ const prePoint2 = points[points.length - 2];
322
+ if (prePoint2.lineWidth && prePoint.lineWidth) {
323
+ const rate =
324
+ (point.lineWidth - prePoint.lineWidth) / prePoint.lineWidth;
325
+ const maxRate = 0.2; // 最大变化率20%
326
+ if (Math.abs(rate) > maxRate) {
327
+ const per = rate > 0 ? maxRate : -maxRate;
328
+ point.lineWidth = prePoint.lineWidth * (1 + per);
329
+ }
330
+ }
331
+ }
332
+ }
333
+
334
+ points.push(point);
335
+
336
+ // 非笔锋模式直接使用线段连接
337
+ if (!props.pressure) {
338
+ ctx.beginPath();
339
+ ctx.moveTo(prePoint.x, prePoint.y);
340
+ ctx.lineTo(point.x, point.y);
341
+ ctx.stroke();
342
+ ctx.draw(true);
343
+ } else if (points.length >= 2) {
344
+ // 笔锋模式使用贝塞尔曲线
345
+ drawSmoothLine(prePoint, point);
346
+ }
347
+ }
348
+
349
+ emit("signing", e);
350
+ };
351
+
352
+ /**
353
+ * @description 重绘整个画布
354
+ * */
355
+ const redrawCanvas = () => {
356
+ const { ctx } = canvasState;
357
+ if (!ctx) return;
358
+
359
+ // 清除画布并设置背景
360
+ if (props.backgroundColor) {
361
+ ctx.setFillStyle(props.backgroundColor);
362
+ ctx.fillRect(0, 0, canvasState.canvasWidth, canvasState.canvasHeight);
363
+ } else {
364
+ ctx.clearRect(0, 0, canvasState.canvasWidth, canvasState.canvasHeight);
365
+ }
366
+
367
+ // 如果没有线条,只需要清空画布
368
+ if (lines.value.length === 0) {
369
+ ctx.draw();
370
+ return;
371
+ }
372
+
373
+ // 收集所有绘制操作,最后一次性 draw
374
+ lines.value.forEach((line) => {
375
+ if (!line.points.length) return;
376
+
377
+ ctx.setStrokeStyle(line.color);
378
+ ctx.setLineJoin("round");
379
+ ctx.setLineCap("round");
380
+
381
+ if (line.isPressure && props.pressure) {
382
+ // 笔锋模式的重绘
383
+ line.points.forEach((point, index) => {
384
+ if (index === 0) return;
385
+ const prePoint = line.points[index - 1];
386
+ const dis_x = point.x - prePoint.x;
387
+ const dis_y = point.y - prePoint.y;
388
+ const distance = Math.sqrt(dis_x * dis_x + dis_y * dis_y);
389
+
390
+ if (distance <= 2) {
391
+ point.lastX1 = point.lastX2 = prePoint.x + dis_x * 0.5;
392
+ point.lastY1 = point.lastY2 = prePoint.y + dis_y * 0.5;
393
+ } else {
394
+ const speed = point.speed || 0;
395
+ const minSpeed = props.minSpeed || 1.5;
396
+ const speedFactor = Math.max(
397
+ 0.1,
398
+ Math.min(0.9, speed / (minSpeed * 10)),
399
+ );
400
+
401
+ point.lastX1 = prePoint.x + dis_x * (0.2 + speedFactor * 0.3);
402
+ point.lastY1 = prePoint.y + dis_y * (0.2 + speedFactor * 0.3);
403
+ point.lastX2 = prePoint.x + dis_x * (0.8 - speedFactor * 0.3);
404
+ point.lastY2 = prePoint.y + dis_y * (0.8 - speedFactor * 0.3);
405
+ }
406
+
407
+ const lineWidth = point.lineWidth || line.width;
408
+ point.isFirstPoint = true;
409
+ });
410
+ } else {
411
+ // 非笔锋模式的重绘
412
+ ctx.setLineWidth(line.width);
413
+ line.points.forEach((point, index) => {
414
+ if (index === 0) return;
415
+ const prePoint = line.points[index - 1];
416
+ ctx.beginPath();
417
+ ctx.moveTo(prePoint.x, prePoint.y);
418
+ ctx.lineTo(point.x, point.y);
419
+ ctx.stroke();
420
+ });
421
+ }
422
+ });
423
+
424
+ // 所有线条绘制完成后,一次性更新画布
425
+ ctx.draw();
426
+ };
427
+
428
+ /**
429
+ * @description 修改撤销功能
430
+ * */
431
+ const revoke = () => {
432
+ if (!lines.value.length) return;
433
+ const step = Math.min(props.step, lines.value.length);
434
+ const removedLines = lines.value.splice(lines.value.length - step);
435
+ redoLines.value.push(...removedLines);
436
+ currentStep.value = Math.max(0, currentStep.value - step);
437
+ redrawCanvas();
438
+ };
439
+
440
+ /**
441
+ * @description 修改恢复功能
442
+ * */
443
+ const restore = () => {
444
+ if (!redoLines.value.length) return;
445
+ const step = Math.min(props.step, redoLines.value.length);
446
+ const restoredLines = redoLines.value.splice(redoLines.value.length - step);
447
+ lines.value.push(...restoredLines);
448
+ currentStep.value = Math.min(lines.value.length, currentStep.value + step);
449
+ redrawCanvas();
450
+ };
451
+
452
+ /**
453
+ * @description 添加平滑线条绘制方法
454
+ * */
455
+ function drawSmoothLine(prePoint: Point, point: Point) {
456
+ const { ctx } = canvasState;
457
+ if (!ctx) return;
458
+
459
+ // 计算两点间距离
460
+ const dis_x = point.x - prePoint.x;
461
+ const dis_y = point.y - prePoint.y;
462
+ const distance = Math.sqrt(dis_x * dis_x + dis_y * dis_y);
463
+
464
+ if (distance <= 2) {
465
+ // 对于非常近的点,直接使用中点
466
+ point.lastX1 = point.lastX2 = prePoint.x + dis_x * 0.5;
467
+ point.lastY1 = point.lastY2 = prePoint.y + dis_y * 0.5;
468
+ } else {
469
+ // 根据点的速度计算控制点的偏移程度
470
+ const speed = point.speed || 0;
471
+ const minSpeed = props.minSpeed || 1.5;
472
+ const speedFactor = Math.max(0.1, Math.min(0.9, speed / (minSpeed * 10)));
473
+
474
+ // 计算控制点
475
+ point.lastX1 = prePoint.x + dis_x * (0.2 + speedFactor * 0.3);
476
+ point.lastY1 = prePoint.y + dis_y * (0.2 + speedFactor * 0.3);
477
+ point.lastX2 = prePoint.x + dis_x * (0.8 - speedFactor * 0.3);
478
+ point.lastY2 = prePoint.y + dis_y * (0.8 - speedFactor * 0.3);
479
+ }
480
+
481
+ // 计算线宽
482
+ const lineWidth = point.lineWidth || props.lineWidth;
483
+
484
+ // 绘制贝塞尔曲线
485
+ if (typeof prePoint.lastX1 === "number") {
486
+ // 设置线宽
487
+ ctx.setLineWidth(lineWidth);
488
+ // 绘制第一段曲线
489
+ ctx.beginPath();
490
+ ctx.moveTo(prePoint.lastX2!, prePoint.lastY2!);
491
+ ctx.quadraticCurveTo(prePoint.x, prePoint.y, point.lastX1, point.lastY1);
492
+ ctx.stroke();
493
+
494
+ if (!prePoint.isFirstPoint) {
495
+ // 绘制连接段曲线
496
+ ctx.beginPath();
497
+ ctx.moveTo(prePoint.lastX1!, prePoint.lastY1!);
498
+ ctx.quadraticCurveTo(
499
+ prePoint.x,
500
+ prePoint.y,
501
+ prePoint.lastX2!,
502
+ prePoint.lastY2!,
503
+ );
504
+ ctx.stroke();
505
+ }
506
+
507
+ // 批量更新绘制内容
508
+ ctx.draw(true);
509
+ } else {
510
+ point.isFirstPoint = true;
511
+ }
512
+ }
513
+
514
+ onMounted(() => {
515
+ initCanvas();
516
+ });
517
+
518
+ onBeforeMount(() => {
519
+ // #ifdef MP
520
+ pixelRatio.value = uni.getSystemInfoSync().pixelRatio;
521
+ // #endif
522
+ });
523
+
524
+ /**
525
+ * @description 获取canvas上下文
526
+ */
527
+ function getContext() {
528
+ return new Promise<UniApp.CanvasContext>((resolve) => {
529
+ const { ctx } = canvasState;
530
+
531
+ if (ctx) {
532
+ return resolve(ctx);
533
+ }
534
+ // #ifndef MP-WEIXIN
535
+ getRect(`#${canvasId.value}`, false, instance).then((canvasRect) => {
536
+ setCanvasState(canvasRect.width!, canvasRect.height!);
537
+ canvasState.ctx = uni.createCanvasContext(canvasId.value, instance.proxy);
538
+ if (canvasState.ctx) {
539
+ canvasState.ctx.scale(pixelRatio.value, pixelRatio.value);
540
+ }
541
+ resolve(canvasState.ctx);
542
+ });
543
+ // #endif
544
+ // #ifdef MP-WEIXIN
545
+
546
+ getRect(`#${canvasId.value}`, false, instance, true).then(
547
+ (canvasRect: any) => {
548
+ if (
549
+ canvasRect &&
550
+ canvasRect.node &&
551
+ canvasRect.width &&
552
+ canvasRect.height
553
+ ) {
554
+ const canvasInstance = canvasRect.node;
555
+ canvasState.ctx = canvas2dAdapter(
556
+ canvasInstance.getContext("2d") as CanvasRenderingContext2D,
557
+ );
558
+ canvasInstance.width = canvasRect.width * pixelRatio.value;
559
+ canvasInstance.height = canvasRect.height * pixelRatio.value;
560
+ canvasState.ctx.scale(pixelRatio.value, pixelRatio.value);
561
+ canvas = canvasInstance;
562
+ setCanvasState(canvasRect.width, canvasRect.height);
563
+ resolve(canvasState.ctx);
564
+ }
565
+ },
566
+ );
567
+ // #endif
568
+ });
569
+ }
570
+
571
+ /**
572
+ * @description 设置 canvasState
573
+ */
574
+ function setCanvasState(width: number, height: number) {
575
+ canvasState.canvasHeight = height * pixelRatio.value;
576
+ canvasState.canvasWidth = width * pixelRatio.value;
577
+ }
578
+
579
+ /**
580
+ * @description 设置线段
581
+ * */
582
+ function setLine() {
583
+ const { ctx } = canvasState;
584
+ if (ctx) {
585
+ ctx.setLineWidth(getDefaultLineWidth()); // 使用新的默认宽度
586
+ ctx.setStrokeStyle(props.penColor);
587
+ ctx.setLineJoin("round");
588
+ ctx.setLineCap("round");
589
+ }
590
+ }
591
+
592
+ /**
593
+ * @description canvas 绘制图片输出成文件类型
594
+ */
595
+ function canvasToImage() {
596
+ const { fileType, quality, exportScale } = props;
597
+ const { canvasWidth, canvasHeight } = canvasState;
598
+ uni.canvasToTempFilePath(
599
+ {
600
+ width: canvasWidth * exportScale,
601
+ height: canvasHeight * exportScale,
602
+ destWidth: canvasWidth * exportScale,
603
+ destHeight: canvasHeight * exportScale,
604
+ fileType,
605
+ quality,
606
+ canvasId: canvasId.value,
607
+ canvas: canvas,
608
+ success: (res) => {
609
+ const result: SignatureResult = {
610
+ tempFilePath: res.tempFilePath,
611
+ width: (canvasWidth * exportScale) / pixelRatio.value,
612
+ height: (canvasHeight * exportScale) / pixelRatio.value,
613
+ success: true,
614
+ };
615
+ // #ifdef MP-DINGTALK
616
+ result.tempFilePath = (res as any).filePath;
617
+ // #endif
618
+ emit("confirm", result);
619
+ },
620
+ fail: () => {
621
+ const result: SignatureResult = {
622
+ tempFilePath: "",
623
+ width: (canvasWidth * exportScale) / pixelRatio.value,
624
+ height: (canvasHeight * exportScale) / pixelRatio.value,
625
+ success: false,
626
+ };
627
+ emit("confirm", result);
628
+ },
629
+ },
630
+ instance.proxy,
631
+ );
632
+ }
633
+
634
+ function clearCanvas() {
635
+ const { canvasWidth, canvasHeight, ctx } = canvasState;
636
+ if (ctx) {
637
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
638
+ if (props.backgroundColor) {
639
+ ctx.setFillStyle(props.backgroundColor);
640
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
641
+ }
642
+ ctx.draw();
643
+ }
644
+ }
645
+
646
+ defineExpose<SignatureExpose>({
647
+ init: initCanvas,
648
+ clear,
649
+ confirm: confirmSignature,
650
+ restore,
651
+ revoke,
652
+ });
653
+ </script>
654
+ <style scoped lang="scss">
655
+ @import "./index.scss";
656
+ </style>
@@ -0,0 +1,29 @@
1
+ @use "../../theme.scss" as *;
2
+ @use "../../libs/css/mixin.scss" as *;
3
+
4
+ @include b(signature) {
5
+ @include e(content) {
6
+ justify-content: center;
7
+ align-items: center;
8
+ display: flex;
9
+ overflow: hidden;
10
+ background: $hy-background--3;
11
+ border-radius: $hy-border-radius-base;
12
+ border: $hy-border-line;
13
+ }
14
+
15
+ @include e(content-canvas) {
16
+ width: 100%;
17
+ }
18
+
19
+
20
+ @include e(footer) {
21
+ margin-top: $hy-border-margin-padding-base;
22
+ justify-content: flex-end;
23
+ display: flex;
24
+
25
+ :deep(.hy-button) {
26
+ margin-left: $hy-border-margin-padding-base;
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,29 @@
1
+ import type IProps from "./typing";
2
+
3
+ const defaultProps: IProps = {
4
+ penColor: "#000",
5
+ lineWidth: 2,
6
+ clearText: "清空",
7
+ revokeText: "撤销",
8
+ restoreText: "恢复",
9
+ confirmText: "确认",
10
+ fileType: "png",
11
+ quality: 1,
12
+ exportScale: 1,
13
+ disabled: false,
14
+ height: 1,
15
+ width: 1,
16
+ round: "10rpx",
17
+ backgroundColor: "",
18
+ disableScroll: true,
19
+ enableHistory: false,
20
+ step: 1,
21
+ undoText: "",
22
+ redoText: "",
23
+ pressure: false,
24
+ minWidth: 2,
25
+ maxWidth: 6,
26
+ minSpeed: 1.5,
27
+ };
28
+
29
+ export default defaultProps;