hy-app 0.3.0 → 0.3.2

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 (108) hide show
  1. package/README.md +6 -3
  2. package/common/shakeService.ts +31 -29
  3. package/components/avatar.zip +0 -0
  4. package/components/hy-action-sheet/hy-action-sheet.vue +71 -46
  5. package/components/hy-address-picker/hy-address-picker.vue +94 -83
  6. package/components/hy-avatar/hy-avatar.vue +84 -85
  7. package/components/hy-back-top/hy-back-top.vue +8 -6
  8. package/components/hy-badge/hy-badge.vue +47 -46
  9. package/components/hy-button/hy-button.vue +117 -93
  10. package/components/hy-calendar/hy-calendar.vue +168 -160
  11. package/components/hy-card/hy-card.vue +50 -43
  12. package/components/hy-card/typing.d.ts +33 -32
  13. package/components/hy-cell/hy-cell.vue +73 -51
  14. package/components/hy-check-button/hy-check-button.vue +54 -47
  15. package/components/hy-checkbox/hy-checkbox.vue +97 -105
  16. package/components/hy-code-input/hy-code-input.vue +80 -89
  17. package/components/hy-config-provider/hy-config-provider.vue +20 -21
  18. package/components/hy-count-down/hy-count-down.vue +66 -67
  19. package/components/hy-count-to/hy-count-to.vue +105 -99
  20. package/components/hy-count-to/typing.d.ts +13 -12
  21. package/components/hy-datetime-picker/hy-datetime-picker.vue +261 -253
  22. package/components/hy-datetime-picker/typing.d.ts +42 -40
  23. package/components/hy-divider/hy-divider.vue +68 -73
  24. package/components/hy-dropdown/hy-dropdown.vue +20 -19
  25. package/components/hy-dropdown-item/hy-dropdown-item.vue +66 -61
  26. package/components/hy-dropdown-item/typing.d.ts +9 -9
  27. package/components/hy-empty/hy-empty.vue +42 -42
  28. package/components/hy-flex/hy-flex.vue +99 -0
  29. package/components/hy-flex/index.scss +8 -0
  30. package/components/hy-flex/typing.d.ts +23 -0
  31. package/components/hy-float-button/hy-float-button.vue +218 -210
  32. package/components/hy-folding-panel/hy-folding-panel.vue +32 -33
  33. package/components/hy-form/hy-form.vue +264 -252
  34. package/components/hy-form/typing.d.ts +4 -0
  35. package/components/hy-form-group/hy-form-group.vue +114 -183
  36. package/components/hy-form-item/hy-form-item.vue +12 -10
  37. package/components/hy-form-item/index.scss +2 -2
  38. package/components/hy-form-item/typing.d.ts +3 -6
  39. package/components/hy-grid/hy-grid.vue +44 -43
  40. package/components/hy-icon/hy-icon.vue +61 -67
  41. package/components/hy-image/hy-image.vue +112 -88
  42. package/components/hy-image/typing.d.ts +27 -23
  43. package/components/hy-input/hy-input.vue +157 -127
  44. package/components/hy-input/typing.d.ts +53 -47
  45. package/components/hy-line/hy-line.vue +26 -26
  46. package/components/hy-line-progress/hy-line-progress.vue +42 -35
  47. package/components/hy-list/hy-list.vue +76 -85
  48. package/components/hy-loading/hy-loading.vue +26 -23
  49. package/components/hy-login/TheUserLogin.vue +1 -1
  50. package/components/hy-menu/hy-menu.vue +48 -43
  51. package/components/hy-menu/typing.d.ts +18 -17
  52. package/components/hy-modal/hy-modal.vue +39 -35
  53. package/components/hy-navbar/hy-navbar.vue +25 -25
  54. package/components/hy-navbar/typing.d.ts +24 -22
  55. package/components/hy-notice-bar/hy-notice-bar.vue +26 -27
  56. package/components/hy-notify/hy-notify.vue +53 -53
  57. package/components/hy-number-step/hy-number-step.vue +134 -146
  58. package/components/hy-number-step/typing.d.ts +35 -35
  59. package/components/hy-overlay/hy-overlay.vue +23 -21
  60. package/components/hy-pagination/hy-pagination.vue +41 -36
  61. package/components/hy-picker/hy-picker.vue +184 -154
  62. package/components/hy-picker/typing.d.ts +39 -39
  63. package/components/hy-popover/hy-popover.vue +97 -77
  64. package/components/hy-popup/hy-popup.vue +107 -98
  65. package/components/hy-price/hy-price.vue +38 -34
  66. package/components/hy-qrcode/hy-qrcode.vue +50 -51
  67. package/components/hy-radio/hy-radio.vue +101 -113
  68. package/components/hy-rate/hy-rate.vue +107 -88
  69. package/components/hy-read-more/hy-read-more.vue +64 -49
  70. package/components/hy-scroll-list/hy-scroll-list.vue +45 -48
  71. package/components/hy-search/hy-search.vue +73 -66
  72. package/components/hy-search/typing.d.ts +36 -35
  73. package/components/hy-signature/hy-signature.vue +282 -240
  74. package/components/hy-slider/hy-slider.vue +195 -153
  75. package/components/hy-slider/typing.d.ts +21 -21
  76. package/components/hy-steps/hy-steps.vue +118 -90
  77. package/components/hy-steps/index.scss +31 -21
  78. package/components/hy-submit-bar/hy-submit-bar.vue +61 -70
  79. package/components/hy-subsection/hy-subsection.vue +99 -102
  80. package/components/hy-subsection/typing.d.ts +19 -19
  81. package/components/hy-swipe-action/hy-swipe-action.vue +131 -118
  82. package/components/hy-swiper/hy-swiper.vue +85 -71
  83. package/components/hy-switch/hy-switch.vue +67 -72
  84. package/components/hy-switch/typing.d.ts +21 -19
  85. package/components/hy-tabs/hy-tabs.vue +168 -113
  86. package/components/hy-tag/hy-tag.vue +90 -86
  87. package/components/hy-tag/typing.d.ts +26 -21
  88. package/components/hy-text/hy-text.vue +119 -111
  89. package/components/hy-textarea/hy-textarea.vue +100 -93
  90. package/components/hy-textarea/typing.d.ts +36 -31
  91. package/components/hy-toast/hy-toast.vue +77 -67
  92. package/components/hy-tooltip/hy-tooltip.vue +109 -91
  93. package/components/hy-transition/hy-transition.vue +62 -66
  94. package/components/hy-upload/hy-upload.vue +294 -152
  95. package/components/hy-upload/typing.d.ts +41 -36
  96. package/components/hy-warn/hy-warn.vue +34 -27
  97. package/components/hy-waterfall/hy-waterfall.vue +83 -74
  98. package/components/hy-watermark/hy-watermark.vue +134 -115
  99. package/components/index.ts +1 -1
  100. package/composables/usePopover.ts +236 -221
  101. package/composables/useQueue.ts +53 -52
  102. package/global.d.ts +1 -0
  103. package/package.json +2 -2
  104. package/store/index.ts +9 -1
  105. package/theme.scss +5 -5
  106. package/typing/index.ts +0 -1
  107. package/typing/modules/common.d.ts +0 -2
  108. package/web-types.json +1 -1
@@ -1,6 +1,9 @@
1
1
  <template>
2
2
  <view :class="['hy-signature', customClass]" :style="customStyle">
3
- <view class="hy-signature__content" :style="{ borderRadius: addUnit(round) }">
3
+ <view
4
+ class="hy-signature__content"
5
+ :style="{ borderRadius: addUnit(round) }"
6
+ >
4
7
  <!-- #ifdef MP-WEIXIN -->
5
8
  <canvas
6
9
  class="hy-signature__content-canvas"
@@ -61,7 +64,13 @@
61
64
  :text="restoreText"
62
65
  ></hy-button>
63
66
  </block>
64
- <hy-button size="small" plain shape="circle" @click="clear" :text="clearText"></hy-button>
67
+ <hy-button
68
+ size="small"
69
+ plain
70
+ shape="circle"
71
+ @click="clear"
72
+ :text="clearText"
73
+ ></hy-button>
65
74
  <hy-button
66
75
  size="small"
67
76
  shape="circle"
@@ -72,40 +81,56 @@
72
81
  </view>
73
82
  </view>
74
83
  </template>
84
+
75
85
  <script lang="ts">
76
86
  export default {
77
- name: 'hy-signature',
87
+ name: "hy-signature",
78
88
  options: {
79
89
  addGlobalClass: true,
80
90
  virtualHost: true,
81
- styleIsolation: 'shared',
91
+ styleIsolation: "shared",
82
92
  },
83
- }
93
+ };
84
94
  </script>
95
+
85
96
  <script lang="ts" setup>
86
- import { computed, getCurrentInstance, onBeforeMount, onMounted, reactive, ref, watch } from 'vue'
87
- import type { CSSProperties, PropType } from 'vue'
88
- import { addUnit, getRect, guid } from '../../utils'
89
- import type { SignatureExpose, SignatureResult, Point, Line, ISignatureEmits } from './typing'
97
+ import {
98
+ computed,
99
+ getCurrentInstance,
100
+ onBeforeMount,
101
+ onMounted,
102
+ reactive,
103
+ ref,
104
+ watch,
105
+ } from "vue";
106
+ import type { CSSProperties, PropType } from "vue";
107
+ import { addUnit, getRect, guid } from "../../utils";
108
+ import type {
109
+ SignatureExpose,
110
+ SignatureResult,
111
+ Point,
112
+ Line,
113
+ ISignatureEmits,
114
+ } from "./typing";
90
115
  // #ifdef MP-WEIXIN
91
- import { canvas2dAdapter } from './canvasHelper'
116
+ import { canvas2dAdapter } from "./canvasHelper";
92
117
  // #endif
93
118
 
94
119
  // 组件
95
- import HyButton from '../hy-button/hy-button.vue'
120
+ import HyButton from "../hy-button/hy-button.vue";
96
121
 
97
122
  /**
98
123
  * 用于签名场景,基于 Canvas 实现的签名组件。提供了基础签名、历史记录、笔锋效果等功能。
99
124
  * @displayName hy-signature
100
125
  */
101
- defineOptions({})
126
+ defineOptions({});
102
127
 
103
128
  // const props = withDefaults(defineProps<IProps>(), defaultProps);
104
129
  const props = defineProps({
105
130
  /** 签名笔颜色 */
106
131
  penColor: {
107
132
  type: String,
108
- default: '#000',
133
+ default: "#000",
109
134
  },
110
135
  /** 签名笔宽度 */
111
136
  lineWidth: {
@@ -115,27 +140,27 @@ const props = defineProps({
115
140
  /** 清空按钮的文本 */
116
141
  clearText: {
117
142
  type: String,
118
- default: '清空',
143
+ default: "清空",
119
144
  },
120
145
  /** 撤回按钮的文本 */
121
146
  revokeText: {
122
147
  type: String,
123
- default: '撤销',
148
+ default: "撤销",
124
149
  },
125
150
  /** 恢复按钮的文本 */
126
151
  restoreText: {
127
152
  type: String,
128
- default: '恢复',
153
+ default: "恢复",
129
154
  },
130
155
  /** 确认按钮的文本 */
131
156
  confirmText: {
132
157
  type: String,
133
- default: '确认',
158
+ default: "确认",
134
159
  },
135
160
  /** 目标文件的类型 */
136
161
  fileType: {
137
162
  type: String,
138
- default: 'png',
163
+ default: "png",
139
164
  },
140
165
  /** 签名笔颜色 */
141
166
  quality: {
@@ -165,7 +190,7 @@ const props = defineProps({
165
190
  /** 边框圆角 */
166
191
  round: {
167
192
  type: String,
168
- default: '10rpx',
193
+ default: "10rpx",
169
194
  },
170
195
  /** 画板的背景色 */
171
196
  backgroundColor: String,
@@ -214,66 +239,67 @@ const props = defineProps({
214
239
  },
215
240
  /** 自定义外部类名 */
216
241
  customClass: String,
217
- })
218
- const emit = defineEmits<ISignatureEmits>()
219
- const instance = getCurrentInstance() as any
220
- const canvasId = ref<string>(`signature${guid()}`) // canvas 组件的唯一标识符
221
- let canvas: null = null //canvas对象 微信小程序生成图片必须传入
222
- const drawing = ref<boolean>(false) // 是否正在绘制
223
- const pixelRatio = ref<number>(1) // 像素比
242
+ });
243
+ const emit = defineEmits<ISignatureEmits>();
244
+ const instance = getCurrentInstance() as any;
245
+ const canvasId = ref<string>(`signature${guid()}`); // canvas 组件的唯一标识符
246
+ let canvas: null = null; //canvas对象 微信小程序生成图片必须传入
247
+ const drawing = ref<boolean>(false); // 是否正在绘制
248
+ const pixelRatio = ref<number>(1); // 像素比
224
249
 
225
250
  const canvasState = reactive({
226
251
  canvasWidth: 0,
227
252
  canvasHeight: 0,
228
253
  ctx: null as UniApp.CanvasContext | null, // canvas上下文
229
- })
254
+ });
230
255
 
231
256
  watch(
232
257
  () => props.penColor,
233
258
  () => {
234
- setLine()
259
+ setLine();
235
260
  },
236
- )
261
+ );
237
262
 
238
263
  watch(
239
264
  () => props.lineWidth,
240
265
  () => {
241
- setLine()
266
+ setLine();
242
267
  },
243
- )
268
+ );
244
269
 
245
270
  const canvasStyle = computed(() => {
246
- const style: CSSProperties = {}
271
+ const style: CSSProperties = {};
247
272
  if (props.width) {
248
- style.width = addUnit(props.width)
273
+ style.width = addUnit(props.width);
249
274
  }
250
275
 
251
276
  if (props.height) {
252
- style.height = addUnit(props.height)
277
+ style.height = addUnit(props.height);
253
278
  }
254
279
 
255
- return `${style}`
256
- })
280
+ return `${style}`;
281
+ });
257
282
 
258
- const disableScroll = computed(() => props.disableScroll)
259
- const enableHistory = computed(() => props.enableHistory)
283
+ const disableScroll = computed(() => props.disableScroll);
284
+ const enableHistory = computed(() => props.enableHistory);
260
285
 
261
- const lines = ref<Line[]>([]) // 保存所有线条
262
- const redoLines = ref<Line[]>([]) // 保存撤销的线条
263
- const currentLine = ref<Line>() // 当前正在绘制的线
264
- const currentStep = ref(0) // 当前步骤
286
+ const lines = ref<Line[]>([]); // 保存所有线条
287
+ const redoLines = ref<Line[]>([]); // 保存撤销的线条
288
+ const currentLine = ref<Line>(); // 当前正在绘制的线
289
+ const currentStep = ref(0); // 当前步骤
265
290
 
266
291
  /**
267
292
  * @description 添加计算笔画宽度的方法
268
293
  * */
269
294
  function calculateLineWidth(speed: number): number {
270
- if (!props.pressure) return props.lineWidth
271
-
272
- const minSpeed = props.minSpeed || 1.5
273
- const limitedSpeed = Math.min(minSpeed * 10, Math.max(minSpeed, speed))
274
- const addWidth = ((props.maxWidth - props.minWidth) * (limitedSpeed - minSpeed)) / minSpeed
275
- const lineWidth = Math.max(props.maxWidth - addWidth, props.minWidth)
276
- return Math.min(lineWidth, props.maxWidth)
295
+ if (!props.pressure) return props.lineWidth;
296
+
297
+ const minSpeed = props.minSpeed || 1.5;
298
+ const limitedSpeed = Math.min(minSpeed * 10, Math.max(minSpeed, speed));
299
+ const addWidth =
300
+ ((props.maxWidth - props.minWidth) * (limitedSpeed - minSpeed)) / minSpeed;
301
+ const lineWidth = Math.max(props.maxWidth - addWidth, props.minWidth);
302
+ return Math.min(lineWidth, props.maxWidth);
277
303
  }
278
304
 
279
305
  /**
@@ -282,22 +308,22 @@ function calculateLineWidth(speed: number): number {
282
308
  const getDefaultLineWidth = () => {
283
309
  if (props.pressure) {
284
310
  // 在压感模式下,使用最大和最小宽度的平均值作为默认值
285
- return (props.maxWidth + props.minWidth) / 2
311
+ return (props.maxWidth + props.minWidth) / 2;
286
312
  }
287
- return props.lineWidth
288
- }
313
+ return props.lineWidth;
314
+ };
289
315
 
290
316
  /**
291
317
  * @description 开始画线
292
318
  * */
293
319
  const startDrawing = (e: any) => {
294
- e.preventDefault()
295
- drawing.value = true
296
- setLine()
297
- emit('start', e)
320
+ e.preventDefault();
321
+ drawing.value = true;
322
+ setLine();
323
+ emit("start", e);
298
324
 
299
325
  // 创建新线条,同时保存当前的所有绘制参数
300
- const { x, y } = e.touches[0]
326
+ const { x, y } = e.touches[0];
301
327
  currentLine.value = {
302
328
  points: [
303
329
  {
@@ -310,19 +336,19 @@ const startDrawing = (e: any) => {
310
336
  width: getDefaultLineWidth(),
311
337
  backgroundColor: props.backgroundColor,
312
338
  isPressure: props.pressure, // 添加笔锋模式标记
313
- }
339
+ };
314
340
 
315
341
  // 清空重做记录
316
- redoLines.value = []
317
- draw(e)
318
- }
342
+ redoLines.value = [];
343
+ draw(e);
344
+ };
319
345
 
320
346
  /**
321
347
  * @description 结束画线
322
348
  * */
323
349
  const stopDrawing = (e: TouchEvent) => {
324
- e.preventDefault()
325
- drawing.value = false
350
+ e.preventDefault();
351
+ drawing.value = false;
326
352
  if (currentLine.value) {
327
353
  // 保存完整的线条信息,包括所有点的参数
328
354
  lines.value.push({
@@ -339,14 +365,14 @@ const stopDrawing = (e: TouchEvent) => {
339
365
  lastY2: point.lastY2,
340
366
  isFirstPoint: point.isFirstPoint,
341
367
  })),
342
- })
343
- currentStep.value = lines.value.length
368
+ });
369
+ currentStep.value = lines.value.length;
344
370
  }
345
- currentLine.value = undefined
346
- const { ctx } = canvasState
347
- if (ctx) ctx.beginPath()
348
- emit('end', e)
349
- }
371
+ currentLine.value = undefined;
372
+ const { ctx } = canvasState;
373
+ if (ctx) ctx.beginPath();
374
+ emit("end", e);
375
+ };
350
376
 
351
377
  /**
352
378
  * @description 初始化 canvas
@@ -355,320 +381,336 @@ const stopDrawing = (e: TouchEvent) => {
355
381
  const initCanvas = (forceUpdate: boolean = false) => {
356
382
  // 如果不是强制更新,且已经初始化过 canvas,则不再重复初始化
357
383
  if (!forceUpdate && canvasState.canvasHeight && canvasState.canvasWidth) {
358
- return
384
+ return;
359
385
  }
360
386
  getContext().then(() => {
361
- const { ctx } = canvasState
387
+ const { ctx } = canvasState;
362
388
  if (ctx && props.backgroundColor) {
363
- ctx.setFillStyle(props.backgroundColor)
364
- ctx.fillRect(0, 0, canvasState.canvasWidth, canvasState.canvasHeight)
365
- ctx.draw()
389
+ ctx.setFillStyle(props.backgroundColor);
390
+ ctx.fillRect(0, 0, canvasState.canvasWidth, canvasState.canvasHeight);
391
+ ctx.draw();
366
392
  }
367
- })
368
- }
393
+ });
394
+ };
369
395
 
370
396
  /**
371
397
  * @description 清空 canvas
372
398
  * */
373
399
  const clear = () => {
374
- lines.value = []
375
- redoLines.value = []
376
- currentStep.value = 0
377
- clearCanvas()
378
- emit('clear')
379
- }
400
+ lines.value = [];
401
+ redoLines.value = [];
402
+ currentStep.value = 0;
403
+ clearCanvas();
404
+ emit("clear");
405
+ };
380
406
 
381
407
  // 确认签名
382
408
  const confirmSignature = () => {
383
- canvasToImage()
384
- }
409
+ canvasToImage();
410
+ };
385
411
 
386
412
  /**
387
413
  * @description canvas划线
388
414
  * */
389
415
  const draw = (e: any) => {
390
- e.preventDefault()
391
- const { ctx } = canvasState
416
+ e.preventDefault();
417
+ const { ctx } = canvasState;
392
418
 
393
- if (!drawing.value || props.disabled || !ctx) return
394
- const { x, y } = e.touches[0]
419
+ if (!drawing.value || props.disabled || !ctx) return;
420
+ const { x, y } = e.touches[0];
395
421
 
396
422
  const point: Point = {
397
423
  x,
398
424
  y,
399
425
  t: Date.now(),
400
- }
426
+ };
401
427
 
402
428
  if (currentLine.value) {
403
- const points = currentLine.value.points
404
- const prePoint = points[points.length - 1]
429
+ const points = currentLine.value.points;
430
+ const prePoint = points[points.length - 1];
405
431
 
406
432
  if (prePoint.t === point.t || (prePoint.x === x && prePoint.y === y)) {
407
- return
433
+ return;
408
434
  }
409
435
 
410
436
  // 计算点的速度和距离
411
437
  point.distance = Math.sqrt(
412
438
  Math.pow(point.x - prePoint.x, 2) + Math.pow(point.y - prePoint.y, 2),
413
- )
414
- point.speed = point.distance / (point.t - prePoint.t || 0.1)
439
+ );
440
+ point.speed = point.distance / (point.t - prePoint.t || 0.1);
415
441
 
416
442
  if (props.pressure) {
417
- point.lineWidth = calculateLineWidth(point.speed)
443
+ point.lineWidth = calculateLineWidth(point.speed);
418
444
  // 处理线宽变化率限制
419
445
  if (points.length >= 2) {
420
- const prePoint2 = points[points.length - 2]
446
+ const prePoint2 = points[points.length - 2];
421
447
  if (prePoint2.lineWidth && prePoint.lineWidth) {
422
- const rate = (point.lineWidth - prePoint.lineWidth) / prePoint.lineWidth
423
- const maxRate = 0.2 // 最大变化率20%
448
+ const rate =
449
+ (point.lineWidth - prePoint.lineWidth) / prePoint.lineWidth;
450
+ const maxRate = 0.2; // 最大变化率20%
424
451
  if (Math.abs(rate) > maxRate) {
425
- const per = rate > 0 ? maxRate : -maxRate
426
- point.lineWidth = prePoint.lineWidth * (1 + per)
452
+ const per = rate > 0 ? maxRate : -maxRate;
453
+ point.lineWidth = prePoint.lineWidth * (1 + per);
427
454
  }
428
455
  }
429
456
  }
430
457
  }
431
458
 
432
- points.push(point)
459
+ points.push(point);
433
460
 
434
461
  // 非笔锋模式直接使用线段连接
435
462
  if (!props.pressure) {
436
- ctx.beginPath()
437
- ctx.moveTo(prePoint.x, prePoint.y)
438
- ctx.lineTo(point.x, point.y)
439
- ctx.stroke()
440
- ctx.draw(true)
463
+ ctx.beginPath();
464
+ ctx.moveTo(prePoint.x, prePoint.y);
465
+ ctx.lineTo(point.x, point.y);
466
+ ctx.stroke();
467
+ ctx.draw(true);
441
468
  } else if (points.length >= 2) {
442
469
  // 笔锋模式使用贝塞尔曲线
443
- drawSmoothLine(prePoint, point)
470
+ drawSmoothLine(prePoint, point);
444
471
  }
445
472
  }
446
473
 
447
- emit('signing', e)
448
- }
474
+ emit("signing", e);
475
+ };
449
476
 
450
477
  /**
451
478
  * @description 重绘整个画布
452
479
  * */
453
480
  const redrawCanvas = () => {
454
- const { ctx } = canvasState
455
- if (!ctx) return
481
+ const { ctx } = canvasState;
482
+ if (!ctx) return;
456
483
 
457
484
  // 清除画布并设置背景
458
485
  if (props.backgroundColor) {
459
- ctx.setFillStyle(props.backgroundColor)
460
- ctx.fillRect(0, 0, canvasState.canvasWidth, canvasState.canvasHeight)
486
+ ctx.setFillStyle(props.backgroundColor);
487
+ ctx.fillRect(0, 0, canvasState.canvasWidth, canvasState.canvasHeight);
461
488
  } else {
462
- ctx.clearRect(0, 0, canvasState.canvasWidth, canvasState.canvasHeight)
489
+ ctx.clearRect(0, 0, canvasState.canvasWidth, canvasState.canvasHeight);
463
490
  }
464
491
 
465
492
  // 如果没有线条,只需要清空画布
466
493
  if (lines.value.length === 0) {
467
- ctx.draw()
468
- return
494
+ ctx.draw();
495
+ return;
469
496
  }
470
497
 
471
498
  // 收集所有绘制操作,最后一次性 draw
472
499
  lines.value.forEach((line) => {
473
- if (!line.points.length) return
500
+ if (!line.points.length) return;
474
501
 
475
- ctx.setStrokeStyle(line.color)
476
- ctx.setLineJoin('round')
477
- ctx.setLineCap('round')
502
+ ctx.setStrokeStyle(line.color);
503
+ ctx.setLineJoin("round");
504
+ ctx.setLineCap("round");
478
505
 
479
506
  if (line.isPressure && props.pressure) {
480
507
  // 笔锋模式的重绘
481
508
  line.points.forEach((point, index) => {
482
- if (index === 0) return
483
- const prePoint = line.points[index - 1]
484
- const dis_x = point.x - prePoint.x
485
- const dis_y = point.y - prePoint.y
486
- const distance = Math.sqrt(dis_x * dis_x + dis_y * dis_y)
509
+ if (index === 0) return;
510
+ const prePoint = line.points[index - 1];
511
+ const dis_x = point.x - prePoint.x;
512
+ const dis_y = point.y - prePoint.y;
513
+ const distance = Math.sqrt(dis_x * dis_x + dis_y * dis_y);
487
514
 
488
515
  if (distance <= 2) {
489
- point.lastX1 = point.lastX2 = prePoint.x + dis_x * 0.5
490
- point.lastY1 = point.lastY2 = prePoint.y + dis_y * 0.5
516
+ point.lastX1 = point.lastX2 = prePoint.x + dis_x * 0.5;
517
+ point.lastY1 = point.lastY2 = prePoint.y + dis_y * 0.5;
491
518
  } else {
492
- const speed = point.speed || 0
493
- const minSpeed = props.minSpeed || 1.5
494
- const speedFactor = Math.max(0.1, Math.min(0.9, speed / (minSpeed * 10)))
495
-
496
- point.lastX1 = prePoint.x + dis_x * (0.2 + speedFactor * 0.3)
497
- point.lastY1 = prePoint.y + dis_y * (0.2 + speedFactor * 0.3)
498
- point.lastX2 = prePoint.x + dis_x * (0.8 - speedFactor * 0.3)
499
- point.lastY2 = prePoint.y + dis_y * (0.8 - speedFactor * 0.3)
519
+ const speed = point.speed || 0;
520
+ const minSpeed = props.minSpeed || 1.5;
521
+ const speedFactor = Math.max(
522
+ 0.1,
523
+ Math.min(0.9, speed / (minSpeed * 10)),
524
+ );
525
+
526
+ point.lastX1 = prePoint.x + dis_x * (0.2 + speedFactor * 0.3);
527
+ point.lastY1 = prePoint.y + dis_y * (0.2 + speedFactor * 0.3);
528
+ point.lastX2 = prePoint.x + dis_x * (0.8 - speedFactor * 0.3);
529
+ point.lastY2 = prePoint.y + dis_y * (0.8 - speedFactor * 0.3);
500
530
  }
501
531
 
502
- const lineWidth = point.lineWidth || line.width
503
- point.isFirstPoint = true
504
- })
532
+ const lineWidth = point.lineWidth || line.width;
533
+ point.isFirstPoint = true;
534
+ });
505
535
  } else {
506
536
  // 非笔锋模式的重绘
507
- ctx.setLineWidth(line.width)
537
+ ctx.setLineWidth(line.width);
508
538
  line.points.forEach((point, index) => {
509
- if (index === 0) return
510
- const prePoint = line.points[index - 1]
511
- ctx.beginPath()
512
- ctx.moveTo(prePoint.x, prePoint.y)
513
- ctx.lineTo(point.x, point.y)
514
- ctx.stroke()
515
- })
539
+ if (index === 0) return;
540
+ const prePoint = line.points[index - 1];
541
+ ctx.beginPath();
542
+ ctx.moveTo(prePoint.x, prePoint.y);
543
+ ctx.lineTo(point.x, point.y);
544
+ ctx.stroke();
545
+ });
516
546
  }
517
- })
547
+ });
518
548
 
519
549
  // 所有线条绘制完成后,一次性更新画布
520
- ctx.draw()
521
- }
550
+ ctx.draw();
551
+ };
522
552
 
523
553
  /**
524
554
  * @description 修改撤销功能
525
555
  * */
526
556
  const revoke = () => {
527
- if (!lines.value.length) return
528
- const step = Math.min(props.step, lines.value.length)
529
- const removedLines = lines.value.splice(lines.value.length - step)
530
- redoLines.value.push(...removedLines)
531
- currentStep.value = Math.max(0, currentStep.value - step)
532
- redrawCanvas()
533
- }
557
+ if (!lines.value.length) return;
558
+ const step = Math.min(props.step, lines.value.length);
559
+ const removedLines = lines.value.splice(lines.value.length - step);
560
+ redoLines.value.push(...removedLines);
561
+ currentStep.value = Math.max(0, currentStep.value - step);
562
+ redrawCanvas();
563
+ };
534
564
 
535
565
  /**
536
566
  * @description 修改恢复功能
537
567
  * */
538
568
  const restore = () => {
539
- if (!redoLines.value.length) return
540
- const step = Math.min(props.step, redoLines.value.length)
541
- const restoredLines = redoLines.value.splice(redoLines.value.length - step)
542
- lines.value.push(...restoredLines)
543
- currentStep.value = Math.min(lines.value.length, currentStep.value + step)
544
- redrawCanvas()
545
- }
569
+ if (!redoLines.value.length) return;
570
+ const step = Math.min(props.step, redoLines.value.length);
571
+ const restoredLines = redoLines.value.splice(redoLines.value.length - step);
572
+ lines.value.push(...restoredLines);
573
+ currentStep.value = Math.min(lines.value.length, currentStep.value + step);
574
+ redrawCanvas();
575
+ };
546
576
 
547
577
  /**
548
578
  * @description 添加平滑线条绘制方法
549
579
  * */
550
580
  function drawSmoothLine(prePoint: Point, point: Point) {
551
- const { ctx } = canvasState
552
- if (!ctx) return
581
+ const { ctx } = canvasState;
582
+ if (!ctx) return;
553
583
 
554
584
  // 计算两点间距离
555
- const dis_x = point.x - prePoint.x
556
- const dis_y = point.y - prePoint.y
557
- const distance = Math.sqrt(dis_x * dis_x + dis_y * dis_y)
585
+ const dis_x = point.x - prePoint.x;
586
+ const dis_y = point.y - prePoint.y;
587
+ const distance = Math.sqrt(dis_x * dis_x + dis_y * dis_y);
558
588
 
559
589
  if (distance <= 2) {
560
590
  // 对于非常近的点,直接使用中点
561
- point.lastX1 = point.lastX2 = prePoint.x + dis_x * 0.5
562
- point.lastY1 = point.lastY2 = prePoint.y + dis_y * 0.5
591
+ point.lastX1 = point.lastX2 = prePoint.x + dis_x * 0.5;
592
+ point.lastY1 = point.lastY2 = prePoint.y + dis_y * 0.5;
563
593
  } else {
564
594
  // 根据点的速度计算控制点的偏移程度
565
- const speed = point.speed || 0
566
- const minSpeed = props.minSpeed || 1.5
567
- const speedFactor = Math.max(0.1, Math.min(0.9, speed / (minSpeed * 10)))
595
+ const speed = point.speed || 0;
596
+ const minSpeed = props.minSpeed || 1.5;
597
+ const speedFactor = Math.max(0.1, Math.min(0.9, speed / (minSpeed * 10)));
568
598
 
569
599
  // 计算控制点
570
- point.lastX1 = prePoint.x + dis_x * (0.2 + speedFactor * 0.3)
571
- point.lastY1 = prePoint.y + dis_y * (0.2 + speedFactor * 0.3)
572
- point.lastX2 = prePoint.x + dis_x * (0.8 - speedFactor * 0.3)
573
- point.lastY2 = prePoint.y + dis_y * (0.8 - speedFactor * 0.3)
600
+ point.lastX1 = prePoint.x + dis_x * (0.2 + speedFactor * 0.3);
601
+ point.lastY1 = prePoint.y + dis_y * (0.2 + speedFactor * 0.3);
602
+ point.lastX2 = prePoint.x + dis_x * (0.8 - speedFactor * 0.3);
603
+ point.lastY2 = prePoint.y + dis_y * (0.8 - speedFactor * 0.3);
574
604
  }
575
605
 
576
606
  // 计算线宽
577
- const lineWidth = point.lineWidth || props.lineWidth
607
+ const lineWidth = point.lineWidth || props.lineWidth;
578
608
 
579
609
  // 绘制贝塞尔曲线
580
- if (typeof prePoint.lastX1 === 'number') {
610
+ if (typeof prePoint.lastX1 === "number") {
581
611
  // 设置线宽
582
- ctx.setLineWidth(lineWidth)
612
+ ctx.setLineWidth(lineWidth);
583
613
  // 绘制第一段曲线
584
- ctx.beginPath()
585
- ctx.moveTo(prePoint.lastX2!, prePoint.lastY2!)
586
- ctx.quadraticCurveTo(prePoint.x, prePoint.y, point.lastX1, point.lastY1)
587
- ctx.stroke()
614
+ ctx.beginPath();
615
+ ctx.moveTo(prePoint.lastX2!, prePoint.lastY2!);
616
+ ctx.quadraticCurveTo(prePoint.x, prePoint.y, point.lastX1, point.lastY1);
617
+ ctx.stroke();
588
618
 
589
619
  if (!prePoint.isFirstPoint) {
590
620
  // 绘制连接段曲线
591
- ctx.beginPath()
592
- ctx.moveTo(prePoint.lastX1!, prePoint.lastY1!)
593
- ctx.quadraticCurveTo(prePoint.x, prePoint.y, prePoint.lastX2!, prePoint.lastY2!)
594
- ctx.stroke()
621
+ ctx.beginPath();
622
+ ctx.moveTo(prePoint.lastX1!, prePoint.lastY1!);
623
+ ctx.quadraticCurveTo(
624
+ prePoint.x,
625
+ prePoint.y,
626
+ prePoint.lastX2!,
627
+ prePoint.lastY2!,
628
+ );
629
+ ctx.stroke();
595
630
  }
596
631
 
597
632
  // 批量更新绘制内容
598
- ctx.draw(true)
633
+ ctx.draw(true);
599
634
  } else {
600
- point.isFirstPoint = true
635
+ point.isFirstPoint = true;
601
636
  }
602
637
  }
603
638
 
604
639
  onMounted(() => {
605
- initCanvas()
606
- })
640
+ initCanvas();
641
+ });
607
642
 
608
643
  onBeforeMount(() => {
609
644
  // #ifdef MP
610
- pixelRatio.value = uni.getSystemInfoSync().pixelRatio
645
+ pixelRatio.value = uni.getSystemInfoSync().pixelRatio;
611
646
  // #endif
612
- })
647
+ });
613
648
 
614
649
  /**
615
650
  * @description 获取canvas上下文
616
651
  */
617
652
  function getContext() {
618
653
  return new Promise<UniApp.CanvasContext>((resolve) => {
619
- const { ctx } = canvasState
654
+ const { ctx } = canvasState;
620
655
 
621
656
  if (ctx) {
622
- return resolve(ctx)
657
+ return resolve(ctx);
623
658
  }
624
659
  // #ifndef MP-WEIXIN
625
660
  getRect(`#${canvasId.value}`, false, instance).then((canvasRect) => {
626
- setCanvasState(canvasRect.width!, canvasRect.height!)
627
- canvasState.ctx = uni.createCanvasContext(canvasId.value, instance.proxy)
661
+ setCanvasState(canvasRect.width!, canvasRect.height!);
662
+ canvasState.ctx = uni.createCanvasContext(canvasId.value, instance.proxy);
628
663
  if (canvasState.ctx) {
629
- canvasState.ctx.scale(pixelRatio.value, pixelRatio.value)
664
+ canvasState.ctx.scale(pixelRatio.value, pixelRatio.value);
630
665
  }
631
- resolve(canvasState.ctx)
632
- })
666
+ resolve(canvasState.ctx);
667
+ });
633
668
  // #endif
634
669
  // #ifdef MP-WEIXIN
635
670
 
636
- getRect(`#${canvasId.value}`, false, instance, true).then((canvasRect: any) => {
637
- if (canvasRect && canvasRect.node && canvasRect.width && canvasRect.height) {
638
- const canvasInstance = canvasRect.node
639
- canvasState.ctx = canvas2dAdapter(
640
- canvasInstance.getContext('2d') as CanvasRenderingContext2D,
641
- )
642
- canvasInstance.width = canvasRect.width * pixelRatio.value
643
- canvasInstance.height = canvasRect.height * pixelRatio.value
644
- canvasState.ctx.scale(pixelRatio.value, pixelRatio.value)
645
- canvas = canvasInstance
646
- setCanvasState(canvasRect.width, canvasRect.height)
647
- resolve(canvasState.ctx)
648
- }
649
- })
671
+ getRect(`#${canvasId.value}`, false, instance, true).then(
672
+ (canvasRect: any) => {
673
+ if (
674
+ canvasRect &&
675
+ canvasRect.node &&
676
+ canvasRect.width &&
677
+ canvasRect.height
678
+ ) {
679
+ const canvasInstance = canvasRect.node;
680
+ canvasState.ctx = canvas2dAdapter(
681
+ canvasInstance.getContext("2d") as CanvasRenderingContext2D,
682
+ );
683
+ canvasInstance.width = canvasRect.width * pixelRatio.value;
684
+ canvasInstance.height = canvasRect.height * pixelRatio.value;
685
+ canvasState.ctx.scale(pixelRatio.value, pixelRatio.value);
686
+ canvas = canvasInstance;
687
+ setCanvasState(canvasRect.width, canvasRect.height);
688
+ resolve(canvasState.ctx);
689
+ }
690
+ },
691
+ );
650
692
  // #endif
651
- })
693
+ });
652
694
  }
653
695
 
654
696
  /**
655
697
  * @description 设置 canvasState
656
698
  */
657
699
  function setCanvasState(width: number, height: number) {
658
- canvasState.canvasHeight = height * pixelRatio.value
659
- canvasState.canvasWidth = width * pixelRatio.value
700
+ canvasState.canvasHeight = height * pixelRatio.value;
701
+ canvasState.canvasWidth = width * pixelRatio.value;
660
702
  }
661
703
 
662
704
  /**
663
705
  * @description 设置线段
664
706
  * */
665
707
  function setLine() {
666
- const { ctx } = canvasState
708
+ const { ctx } = canvasState;
667
709
  if (ctx) {
668
- ctx.setLineWidth(getDefaultLineWidth()) // 使用新的默认宽度
669
- ctx.setStrokeStyle(props.penColor)
670
- ctx.setLineJoin('round')
671
- ctx.setLineCap('round')
710
+ ctx.setLineWidth(getDefaultLineWidth()); // 使用新的默认宽度
711
+ ctx.setStrokeStyle(props.penColor);
712
+ ctx.setLineJoin("round");
713
+ ctx.setLineCap("round");
672
714
  }
673
715
  }
674
716
 
@@ -676,8 +718,8 @@ function setLine() {
676
718
  * @description canvas 绘制图片输出成文件类型
677
719
  */
678
720
  function canvasToImage() {
679
- const { fileType, quality, exportScale } = props
680
- const { canvasWidth, canvasHeight } = canvasState
721
+ const { fileType, quality, exportScale } = props;
722
+ const { canvasWidth, canvasHeight } = canvasState;
681
723
  uni.canvasToTempFilePath(
682
724
  {
683
725
  width: canvasWidth * exportScale,
@@ -694,35 +736,35 @@ function canvasToImage() {
694
736
  width: (canvasWidth * exportScale) / pixelRatio.value,
695
737
  height: (canvasHeight * exportScale) / pixelRatio.value,
696
738
  success: true,
697
- }
739
+ };
698
740
  // #ifdef MP-DINGTALK
699
- result.tempFilePath = (res as any).filePath
741
+ result.tempFilePath = (res as any).filePath;
700
742
  // #endif
701
- emit('confirm', result)
743
+ emit("confirm", result);
702
744
  },
703
745
  fail: () => {
704
746
  const result: SignatureResult = {
705
- tempFilePath: '',
747
+ tempFilePath: "",
706
748
  width: (canvasWidth * exportScale) / pixelRatio.value,
707
749
  height: (canvasHeight * exportScale) / pixelRatio.value,
708
750
  success: false,
709
- }
710
- emit('confirm', result)
751
+ };
752
+ emit("confirm", result);
711
753
  },
712
754
  },
713
755
  instance.proxy,
714
- )
756
+ );
715
757
  }
716
758
 
717
759
  function clearCanvas() {
718
- const { canvasWidth, canvasHeight, ctx } = canvasState
760
+ const { canvasWidth, canvasHeight, ctx } = canvasState;
719
761
  if (ctx) {
720
- ctx.clearRect(0, 0, canvasWidth, canvasHeight)
762
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
721
763
  if (props.backgroundColor) {
722
- ctx.setFillStyle(props.backgroundColor)
723
- ctx.fillRect(0, 0, canvasWidth, canvasHeight)
764
+ ctx.setFillStyle(props.backgroundColor);
765
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
724
766
  }
725
- ctx.draw()
767
+ ctx.draw();
726
768
  }
727
769
  }
728
770
 
@@ -732,8 +774,8 @@ defineExpose<SignatureExpose>({
732
774
  confirm: confirmSignature,
733
775
  restore,
734
776
  revoke,
735
- })
777
+ });
736
778
  </script>
737
779
  <style scoped lang="scss">
738
- @import './index.scss';
780
+ @import "./index.scss";
739
781
  </style>