gxd-uni-library-editx 1.0.40 → 1.0.49-beta2
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.
- package/package.json +1 -1
- package/src/components/XdSignature/XdSignature.vue +475 -0
- package/src/components/XdSignature/context.js +118 -0
- package/src/components/XdSignature/props.js +59 -0
- package/src/components/XdSignature/render.js +140 -0
- package/src/components/XdSignature/signature.js +1 -0
- package/src/components/XdSignature/utils.js +161 -0
package/package.json
CHANGED
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="lime-signature" v-if="show" :style="[canvasStyle, styles]" ref="limeSignature">
|
|
3
|
+
<!-- #ifndef APP-VUE || APP-NVUE -->
|
|
4
|
+
<canvas v-if="useCanvas2d" class="lime-signature__canvas" :id="canvasId" type="2d"
|
|
5
|
+
:disableScroll="disableScroll" @touchstart="touchStart" @touchmove="touchMove"
|
|
6
|
+
@touchend="touchEnd"></canvas>
|
|
7
|
+
<canvas v-else :disableScroll="disableScroll" class="lime-signature__canvas" :canvas-id="canvasId"
|
|
8
|
+
:id="canvasId" :width="canvasWidth" :height="canvasHeight" @touchstart="touchStart" @touchmove="touchMove"
|
|
9
|
+
@touchend="touchEnd" @mousedown="touchStart" @mousemove="touchMove" @mouseup="touchEnd"></canvas>
|
|
10
|
+
<canvas class="offscreen" canvas-id="offscreen" id="offscreen"
|
|
11
|
+
:style="'width:' + offscreenSize[0] + 'px;height:' + offscreenSize[1] + 'px'" :width="offscreenSize[0]"
|
|
12
|
+
:height="offscreenSize[1]">
|
|
13
|
+
</canvas>
|
|
14
|
+
<view v-if="showMask" class="mask" @touchstart="touchStart" @touchmove.stop.prevent="touchMove" @touchend="touchEnd"></view>
|
|
15
|
+
<!-- #endif -->
|
|
16
|
+
<!-- #ifdef APP-VUE -->
|
|
17
|
+
<view :id="canvasId" :disableScroll="disableScroll" :rparam="param" :change:rparam="sign.update"
|
|
18
|
+
:rclear="rclear" :change:rclear="sign.clear" :rundo="rundo" :change:rundo="sign.undo" :rsave="rsave"
|
|
19
|
+
:change:rsave="sign.save" :rempty="rempty" :change:rempty="sign.isEmpty"></view>
|
|
20
|
+
<!-- #endif -->
|
|
21
|
+
<!-- #ifdef APP-NVUE -->
|
|
22
|
+
<web-view src="/uni_modules/lime-signature/hybrid/html/index.html" class="lime-signature__canvas" ref="webview"
|
|
23
|
+
@pagefinish="onPageFinish" @error="onError" @onPostMessage="onMessage"></web-view>
|
|
24
|
+
<!-- #endif -->
|
|
25
|
+
</view>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script>
|
|
29
|
+
// #ifndef APP-NVUE
|
|
30
|
+
import { canIUseCanvas2d, wrapEvent, requestAnimationFrame, sleep , isPC} from './utils'
|
|
31
|
+
import {Signature} from './signature'
|
|
32
|
+
// import {Signature} from '@signature';
|
|
33
|
+
import { uniContext, createImage, toDataURL } from './context'
|
|
34
|
+
// #endif
|
|
35
|
+
import props from './props';
|
|
36
|
+
import { base64ToPath, getRect } from './utils'
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* LimeSignature 手写板签名
|
|
40
|
+
* @description 手写板签名插件:一款能跑在uniapp各端中的签名插件,支持横屏、背景色、笔画颜色、笔画大小等功能,可生成有内容的区域,减小图片尺寸,节省空间。
|
|
41
|
+
* @tutorial https://ext.dcloud.net.cn/plugin?id=4354
|
|
42
|
+
* @property {Number} penSize 画笔大小
|
|
43
|
+
* @property {Number} minLineWidth 线条最小宽
|
|
44
|
+
* @property {Number} maxLineWidth 线条最大宽
|
|
45
|
+
* @property {String} penColor 画笔颜色
|
|
46
|
+
* @property {String} backgroundColor 背景颜色,不填则为透明
|
|
47
|
+
* @property {type} 指定 canvas 类型
|
|
48
|
+
* @value 2d canvas 2d
|
|
49
|
+
* @value '' 非 canvas 2d 旧接口,微信不再维护
|
|
50
|
+
* @property {Boolean} openSmooth 模拟笔锋
|
|
51
|
+
* @property {Number} beforeDelay 延时初始化,在放在弹窗里可以使用 (毫秒)
|
|
52
|
+
* @property {Number} maxHistoryLength 限制历史记录数,即最大可撤销数,传入0则关闭历史记录功能
|
|
53
|
+
* @property {Boolean} landscape 横屏,使用后在最后生成图片时会图片旋转90度
|
|
54
|
+
* @property {Boolean} disableScroll 当在写字时,禁止屏幕滚动以及下拉刷新,nvue无效
|
|
55
|
+
* @property {Boolean} boundingBox 只生成内容区域,即未画部分不生成,有性能的损耗
|
|
56
|
+
*/
|
|
57
|
+
export default {
|
|
58
|
+
props,
|
|
59
|
+
data() {
|
|
60
|
+
return {
|
|
61
|
+
canvasWidth: null,
|
|
62
|
+
canvasHeight: null,
|
|
63
|
+
offscreenWidth: null,
|
|
64
|
+
offscreenHeight: null,
|
|
65
|
+
useCanvas2d: true,
|
|
66
|
+
show: true,
|
|
67
|
+
offscreenStyles: '',
|
|
68
|
+
showMask: false,
|
|
69
|
+
// #ifdef APP-PLUS
|
|
70
|
+
rclear: 0,
|
|
71
|
+
rundo: 0,
|
|
72
|
+
rsave: JSON.stringify({
|
|
73
|
+
n: 0,
|
|
74
|
+
fileType: 'png',
|
|
75
|
+
quality: 1
|
|
76
|
+
}),
|
|
77
|
+
rempty: 0,
|
|
78
|
+
risEmpty: true,
|
|
79
|
+
toDataURL: null,
|
|
80
|
+
tempFilePath: [],
|
|
81
|
+
// #endif
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
computed: {
|
|
85
|
+
canvasId() {
|
|
86
|
+
// #ifdef VUE2
|
|
87
|
+
return `lime-signature${this._uid}`
|
|
88
|
+
// #endif
|
|
89
|
+
// #ifdef VUE3
|
|
90
|
+
return `lime-signature${this._.uid}`
|
|
91
|
+
// #endif
|
|
92
|
+
},
|
|
93
|
+
offscreenId() {
|
|
94
|
+
return this.canvasId + 'offscreen'
|
|
95
|
+
},
|
|
96
|
+
offscreenSize() {
|
|
97
|
+
const {offscreenWidth,offscreenHeight} = this
|
|
98
|
+
return this.landscape ? [offscreenHeight, offscreenWidth] : [offscreenWidth, offscreenHeight]
|
|
99
|
+
},
|
|
100
|
+
canvasStyle() {
|
|
101
|
+
const { canvasWidth, canvasHeight, backgroundColor } = this
|
|
102
|
+
return {
|
|
103
|
+
width: canvasWidth && (canvasWidth + 'px'),
|
|
104
|
+
height: canvasHeight && (canvasHeight + 'px'),
|
|
105
|
+
background: backgroundColor
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
param() {
|
|
109
|
+
const {
|
|
110
|
+
penColor,
|
|
111
|
+
penSize,
|
|
112
|
+
backgroundColor,
|
|
113
|
+
landscape,
|
|
114
|
+
boundingBox,
|
|
115
|
+
openSmooth,
|
|
116
|
+
minLineWidth,
|
|
117
|
+
maxLineWidth,
|
|
118
|
+
minSpeed,
|
|
119
|
+
maxWidthDiffRate,
|
|
120
|
+
maxHistoryLength,
|
|
121
|
+
disableScroll
|
|
122
|
+
} = this
|
|
123
|
+
return JSON.parse(JSON.stringify({
|
|
124
|
+
penColor,
|
|
125
|
+
penSize,
|
|
126
|
+
backgroundColor,
|
|
127
|
+
landscape,
|
|
128
|
+
boundingBox,
|
|
129
|
+
openSmooth,
|
|
130
|
+
minLineWidth,
|
|
131
|
+
maxLineWidth,
|
|
132
|
+
minSpeed,
|
|
133
|
+
maxWidthDiffRate,
|
|
134
|
+
maxHistoryLength,
|
|
135
|
+
disableScroll
|
|
136
|
+
}))
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
// #ifdef APP-NVUE
|
|
140
|
+
watch: {
|
|
141
|
+
param(v) {
|
|
142
|
+
this.$refs.webview.evalJS(`update(${JSON.stringify(v)})`)
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
// #endif
|
|
146
|
+
// #ifndef APP-PLUS
|
|
147
|
+
created() {
|
|
148
|
+
this.useCanvas2d = this.type == '2d' && canIUseCanvas2d() && !isPC
|
|
149
|
+
this.showMask = isPC
|
|
150
|
+
},
|
|
151
|
+
// #endif
|
|
152
|
+
// #ifndef APP-PLUS
|
|
153
|
+
async mounted() {
|
|
154
|
+
if (this.beforeDelay) {
|
|
155
|
+
await sleep(this.beforeDelay)
|
|
156
|
+
}
|
|
157
|
+
const config = await this.getContext()
|
|
158
|
+
this.signature = new Signature(config)
|
|
159
|
+
this.canvasEl = this.signature.canvas.get('el')
|
|
160
|
+
this.offscreenWidth = this.canvasWidth = this.signature.canvas.get('width')
|
|
161
|
+
this.offscreenHeight = this.canvasHeight = this.signature.canvas.get('height')
|
|
162
|
+
|
|
163
|
+
this.stopWatch = this.$watch('param', (v) => {
|
|
164
|
+
this.signature.pen.setOption(v)
|
|
165
|
+
}, {
|
|
166
|
+
immediate: true
|
|
167
|
+
})
|
|
168
|
+
},
|
|
169
|
+
// #endif
|
|
170
|
+
// #ifndef APP-PLUS
|
|
171
|
+
// #ifdef VUE3
|
|
172
|
+
beforeUnmount() {
|
|
173
|
+
this.stopWatch && this.stopWatch()
|
|
174
|
+
this.signature.destroy()
|
|
175
|
+
this.signature = null
|
|
176
|
+
this.show = false;
|
|
177
|
+
},
|
|
178
|
+
// #endif
|
|
179
|
+
// #ifdef VUE2
|
|
180
|
+
beforeDestroy() {
|
|
181
|
+
this.stopWatch && this.stopWatch()
|
|
182
|
+
this.signature.destroy()
|
|
183
|
+
this.show = false;
|
|
184
|
+
this.signature = null
|
|
185
|
+
},
|
|
186
|
+
// #endif
|
|
187
|
+
// #endif
|
|
188
|
+
methods: {
|
|
189
|
+
// #ifdef MP-QQ
|
|
190
|
+
// toJSON() { return this },
|
|
191
|
+
// #endif
|
|
192
|
+
// #ifdef APP-PLUS
|
|
193
|
+
onPageFinish() {
|
|
194
|
+
this.$refs.webview.evalJS(`update(${JSON.stringify(this.param)})`)
|
|
195
|
+
},
|
|
196
|
+
onMessage(e = {}) {
|
|
197
|
+
const {
|
|
198
|
+
detail: {
|
|
199
|
+
data: [res]
|
|
200
|
+
}
|
|
201
|
+
} = e
|
|
202
|
+
if (res.event?.save) {
|
|
203
|
+
this.toDataURL = res.event.save
|
|
204
|
+
}
|
|
205
|
+
if (res.event?.changeSize) {
|
|
206
|
+
const {
|
|
207
|
+
width,
|
|
208
|
+
height
|
|
209
|
+
} = res.event.changeSize
|
|
210
|
+
}
|
|
211
|
+
if (res.event.hasOwnProperty('isEmpty')) {
|
|
212
|
+
this.risEmpty = res.event.isEmpty
|
|
213
|
+
}
|
|
214
|
+
if (res.event?.file) {
|
|
215
|
+
this.tempFilePath.push(res.event.file)
|
|
216
|
+
if (this.tempFilePath.length > 7) {
|
|
217
|
+
this.tempFilePath.shift()
|
|
218
|
+
}
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
if (res.event?.success) {
|
|
222
|
+
if (res.event.success) {
|
|
223
|
+
this.tempFilePath.push(res.event.success)
|
|
224
|
+
if (this.tempFilePath.length > 8) {
|
|
225
|
+
this.tempFilePath.shift()
|
|
226
|
+
}
|
|
227
|
+
this.toDataURL = this.tempFilePath.join('')
|
|
228
|
+
this.tempFilePath = []
|
|
229
|
+
} else {
|
|
230
|
+
this.$emit('fail', 'canvas no data')
|
|
231
|
+
}
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
// #endif
|
|
236
|
+
undo() {
|
|
237
|
+
// #ifdef APP-VUE || APP-NVUE
|
|
238
|
+
this.rundo += 1
|
|
239
|
+
// #endif
|
|
240
|
+
// #ifdef APP-NVUE
|
|
241
|
+
this.$refs.webview.evalJS(`undo()`)
|
|
242
|
+
// #endif
|
|
243
|
+
// #ifndef APP-VUE
|
|
244
|
+
if (this.signature)
|
|
245
|
+
this.signature.undo()
|
|
246
|
+
// #endif
|
|
247
|
+
},
|
|
248
|
+
clear() {
|
|
249
|
+
// #ifdef APP-VUE || APP-NVUE
|
|
250
|
+
this.rclear += 1
|
|
251
|
+
// #endif
|
|
252
|
+
// #ifdef APP-NVUE
|
|
253
|
+
this.$refs.webview.evalJS(`clear()`)
|
|
254
|
+
// #endif
|
|
255
|
+
// #ifndef APP-VUE
|
|
256
|
+
if (this.signature)
|
|
257
|
+
this.signature.clear()
|
|
258
|
+
// #endif
|
|
259
|
+
},
|
|
260
|
+
isEmpty() {
|
|
261
|
+
// #ifdef APP-NVUE
|
|
262
|
+
this.$refs.webview.evalJS(`isEmpty()`)
|
|
263
|
+
// #endif
|
|
264
|
+
// #ifdef APP-VUE || APP-NVUE
|
|
265
|
+
this.rempty += 1
|
|
266
|
+
// #endif
|
|
267
|
+
// #ifndef APP-VUE || APP-NVUE
|
|
268
|
+
return this.signature.isEmpty()
|
|
269
|
+
// #endif
|
|
270
|
+
},
|
|
271
|
+
canvasToTempFilePath(param) {
|
|
272
|
+
const isEmpty = this.isEmpty()
|
|
273
|
+
// #ifdef APP-NVUE
|
|
274
|
+
this.$refs.webview.evalJS(`save()`)
|
|
275
|
+
// #endif
|
|
276
|
+
// #ifdef APP-VUE || APP-NVUE
|
|
277
|
+
const stopURLWatch = this.$watch('toDataURL', (v, n) => {
|
|
278
|
+
if (v && v !== n) {
|
|
279
|
+
// if(param.pathType == 'url') {
|
|
280
|
+
base64ToPath(v).then(res => {
|
|
281
|
+
param.success({
|
|
282
|
+
tempFilePath: res,
|
|
283
|
+
isEmpty: this.risEmpty
|
|
284
|
+
})
|
|
285
|
+
})
|
|
286
|
+
// } else {
|
|
287
|
+
// param.success({tempFilePath: v,isEmpty: this.risEmpty })
|
|
288
|
+
// }
|
|
289
|
+
this.toDataURL = ''
|
|
290
|
+
}
|
|
291
|
+
stopURLWatch && stopURLWatch()
|
|
292
|
+
})
|
|
293
|
+
const {
|
|
294
|
+
fileType,
|
|
295
|
+
quality
|
|
296
|
+
} = param
|
|
297
|
+
const rsave = JSON.parse(this.rsave)
|
|
298
|
+
rsave.n++
|
|
299
|
+
rsave.fileType = fileType
|
|
300
|
+
rsave.quality = quality
|
|
301
|
+
this.rsave = JSON.stringify(rsave)
|
|
302
|
+
// #endif
|
|
303
|
+
// #ifndef APP-VUE || APP-NVUE
|
|
304
|
+
const success = (success) => param.success && param.success(success)
|
|
305
|
+
const fail = (err) => param.fail && param.fail(err)
|
|
306
|
+
const { canvas } = this.signature.canvas.get('el')
|
|
307
|
+
const {
|
|
308
|
+
backgroundColor,
|
|
309
|
+
landscape,
|
|
310
|
+
boundingBox
|
|
311
|
+
} = this
|
|
312
|
+
let width = this.signature.canvas.get('width')
|
|
313
|
+
let height = this.signature.canvas.get('height')
|
|
314
|
+
let x = 0
|
|
315
|
+
let y = 0
|
|
316
|
+
|
|
317
|
+
const canvasToTempFilePath = (image) => {
|
|
318
|
+
const context = uni.createCanvasContext('offscreen', this)
|
|
319
|
+
context.save()
|
|
320
|
+
context.setTransform(1, 0, 0, 1, 0, 0)
|
|
321
|
+
if (landscape) {
|
|
322
|
+
context.translate(0, width)
|
|
323
|
+
context.rotate(-Math.PI / 2)
|
|
324
|
+
}
|
|
325
|
+
if (backgroundColor) {
|
|
326
|
+
context.fillStyle = backgroundColor
|
|
327
|
+
context.fillRect(0, 0, width, height)
|
|
328
|
+
}
|
|
329
|
+
context.drawImage(image, 0, 0, width, height);
|
|
330
|
+
|
|
331
|
+
context.draw(false, () => {
|
|
332
|
+
toDataURL('offscreen', this, param).then((res) => {
|
|
333
|
+
const size = Math.max(width, height)
|
|
334
|
+
context.restore()
|
|
335
|
+
context.clearRect(0, 0, size, size)
|
|
336
|
+
success({
|
|
337
|
+
tempFilePath: res,
|
|
338
|
+
isEmpty
|
|
339
|
+
})
|
|
340
|
+
})
|
|
341
|
+
})
|
|
342
|
+
}
|
|
343
|
+
const next = () => {
|
|
344
|
+
// #ifndef MP-WEIXIN
|
|
345
|
+
const param = { x, y, width, height, canvas }
|
|
346
|
+
// #endif
|
|
347
|
+
|
|
348
|
+
// #ifdef MP-WEIXIN
|
|
349
|
+
const param = { x, y, width, height, canvas: this.useCanvas2d ? canvas : null}
|
|
350
|
+
// #endif
|
|
351
|
+
toDataURL(this.canvasId, this, param).then(canvasToTempFilePath).catch(fail)
|
|
352
|
+
}
|
|
353
|
+
// PC端小程序获取不到 ImageData 数据,长度为0
|
|
354
|
+
if (boundingBox && !isPC) {
|
|
355
|
+
this.signature.getContentBoundingBox(async res => {
|
|
356
|
+
this.offscreenWidth = width = res.width
|
|
357
|
+
this.offscreenHeight = height = res.height
|
|
358
|
+
|
|
359
|
+
x = res.startX
|
|
360
|
+
y = res.startY
|
|
361
|
+
await sleep(100)
|
|
362
|
+
next()
|
|
363
|
+
})
|
|
364
|
+
} else {
|
|
365
|
+
next()
|
|
366
|
+
}
|
|
367
|
+
// #endif
|
|
368
|
+
},
|
|
369
|
+
// #ifndef APP-PLUS
|
|
370
|
+
getContext() {
|
|
371
|
+
return getRect(`#${this.canvasId}`, {
|
|
372
|
+
context: this,
|
|
373
|
+
type: this.useCanvas2d ? 'fields' : 'boundingClientRect'
|
|
374
|
+
}).then(res => {
|
|
375
|
+
if (res) {
|
|
376
|
+
let { width, height, node: canvas, left, top, right} = res
|
|
377
|
+
let {pixelRatio} = uni.getSystemInfoSync()
|
|
378
|
+
let context;
|
|
379
|
+
if (canvas) {
|
|
380
|
+
context = canvas.getContext('2d')
|
|
381
|
+
canvas.width = width * pixelRatio;
|
|
382
|
+
canvas.height = height * pixelRatio;
|
|
383
|
+
} else {
|
|
384
|
+
pixelRatio = 1
|
|
385
|
+
context = uniContext(this.canvasId, this)
|
|
386
|
+
canvas = {
|
|
387
|
+
createImage,
|
|
388
|
+
toDataURL: () => toDataURL(this.canvasId, this),
|
|
389
|
+
requestAnimationFrame
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// 支付宝小程序 使用stroke有个默认背景色
|
|
393
|
+
context.clearRect(0, 0, width, height)
|
|
394
|
+
return {
|
|
395
|
+
left,
|
|
396
|
+
top,
|
|
397
|
+
right,
|
|
398
|
+
width,
|
|
399
|
+
height,
|
|
400
|
+
context,
|
|
401
|
+
canvas,
|
|
402
|
+
pixelRatio
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
})
|
|
406
|
+
},
|
|
407
|
+
getTouch(e) {
|
|
408
|
+
if(isPC && this.canvasRect) {
|
|
409
|
+
e.touches = e.touches.map(item => {
|
|
410
|
+
return {
|
|
411
|
+
...item,
|
|
412
|
+
x: item.clientX - this.canvasRect.left,
|
|
413
|
+
y: item.clientY - this.canvasRect.top,
|
|
414
|
+
}
|
|
415
|
+
})
|
|
416
|
+
}
|
|
417
|
+
return e
|
|
418
|
+
},
|
|
419
|
+
touchStart(e) {
|
|
420
|
+
if (!this.canvasEl) return
|
|
421
|
+
this.isStart = true
|
|
422
|
+
// 微信小程序PC端不支持事件,使用这方法模拟一下
|
|
423
|
+
if(isPC) {
|
|
424
|
+
getRect(`#${this.canvasId}`, {context: this}).then(res => {
|
|
425
|
+
this.canvasRect = res
|
|
426
|
+
this.canvasEl.dispatchEvent('touchstart', wrapEvent(this.getTouch(e)))
|
|
427
|
+
})
|
|
428
|
+
return
|
|
429
|
+
}
|
|
430
|
+
this.canvasEl.dispatchEvent('touchstart', wrapEvent(e))
|
|
431
|
+
},
|
|
432
|
+
touchMove(e) {
|
|
433
|
+
if (!this.canvasEl || !this.isStart && this.canvasEl) return
|
|
434
|
+
this.canvasEl.dispatchEvent('touchmove', wrapEvent(this.getTouch(e)))
|
|
435
|
+
},
|
|
436
|
+
touchEnd(e) {
|
|
437
|
+
if (!this.canvasEl) return
|
|
438
|
+
this.isStart = false
|
|
439
|
+
this.canvasEl.dispatchEvent('touchend', wrapEvent(e))
|
|
440
|
+
},
|
|
441
|
+
// #endif
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
</script>
|
|
445
|
+
<!-- #ifdef APP-VUE -->
|
|
446
|
+
<script module="sign" lang="renderjs">
|
|
447
|
+
import sign from './render'
|
|
448
|
+
export default sign
|
|
449
|
+
</script>
|
|
450
|
+
<!-- #endif -->
|
|
451
|
+
<style lang="scss">
|
|
452
|
+
.lime-signature,
|
|
453
|
+
.lime-signature__canvas {
|
|
454
|
+
/* #ifndef APP-NVUE */
|
|
455
|
+
position: relative;
|
|
456
|
+
width: 100%;
|
|
457
|
+
height: 100%;
|
|
458
|
+
/* #endif */
|
|
459
|
+
/* #ifdef APP-NVUE */
|
|
460
|
+
flex: 1;
|
|
461
|
+
/* #endif */
|
|
462
|
+
}
|
|
463
|
+
.mask {
|
|
464
|
+
position: absolute;
|
|
465
|
+
left: 0;
|
|
466
|
+
right: 0;
|
|
467
|
+
bottom: 0;
|
|
468
|
+
top: 0;
|
|
469
|
+
}
|
|
470
|
+
.offscreen {
|
|
471
|
+
position: fixed;
|
|
472
|
+
top: 0;
|
|
473
|
+
left: 9999px;
|
|
474
|
+
}
|
|
475
|
+
</style>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export const uniContext = (canvasId, context) => {
|
|
2
|
+
let ctx = uni.createCanvasContext(canvasId, context)
|
|
3
|
+
if (!ctx.uniDrawImage) {
|
|
4
|
+
ctx.uniDrawImage = ctx.drawImage
|
|
5
|
+
ctx.drawImage = (image, ...agrs) => {
|
|
6
|
+
ctx.uniDrawImage(image.src, ...agrs)
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
if (!ctx.getImageData) {
|
|
10
|
+
ctx.getImageData = (x, y, width, height) => {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
// #ifdef MP || VUE2
|
|
13
|
+
if (context.proxy) context = context.proxy
|
|
14
|
+
// #endif
|
|
15
|
+
uni.canvasGetImageData({
|
|
16
|
+
canvasId,
|
|
17
|
+
x,
|
|
18
|
+
y,
|
|
19
|
+
width,
|
|
20
|
+
height,
|
|
21
|
+
success(res) {
|
|
22
|
+
resolve(res)
|
|
23
|
+
},
|
|
24
|
+
fail(error) {
|
|
25
|
+
reject(error)
|
|
26
|
+
}
|
|
27
|
+
}, context)
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return ctx
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class Image {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.currentSrc = null
|
|
38
|
+
this.naturalHeight = 0
|
|
39
|
+
this.naturalWidth = 0
|
|
40
|
+
this.width = 0
|
|
41
|
+
this.height = 0
|
|
42
|
+
this.tagName = 'IMG'
|
|
43
|
+
}
|
|
44
|
+
set src(src) {
|
|
45
|
+
this.currentSrc = src
|
|
46
|
+
uni.getImageInfo({
|
|
47
|
+
src,
|
|
48
|
+
success: (res) => {
|
|
49
|
+
this.naturalWidth = this.width = res.width
|
|
50
|
+
this.naturalHeight = this.height = res.height
|
|
51
|
+
this.onload()
|
|
52
|
+
},
|
|
53
|
+
fail: () => {
|
|
54
|
+
this.onerror()
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
get src() {
|
|
59
|
+
return this.currentSrc
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const createImage = () => {
|
|
64
|
+
return new Image()
|
|
65
|
+
}
|
|
66
|
+
export function useCurrentPage() {
|
|
67
|
+
const pages = getCurrentPages();
|
|
68
|
+
return pages[pages.length - 1];
|
|
69
|
+
}
|
|
70
|
+
export const toDataURL = (canvasId, context, options = {}) => {
|
|
71
|
+
// #ifdef MP-QQ
|
|
72
|
+
// context = context.$scope
|
|
73
|
+
// #endif
|
|
74
|
+
// #ifdef MP-ALIPAY
|
|
75
|
+
context = ''
|
|
76
|
+
// #endif
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
let {canvas, width, height, destWidth = 0, destHeight = 0, x = 0, y = 0} = options
|
|
79
|
+
|
|
80
|
+
// #ifdef MP-ALIPAY
|
|
81
|
+
const {pixelRatio} =uni.getSystemInfoSync()
|
|
82
|
+
if(!destWidth || !destHeight) {
|
|
83
|
+
destWidth = width * pixelRatio;
|
|
84
|
+
destHeight = height * pixelRatio;
|
|
85
|
+
width = destWidth;
|
|
86
|
+
height = destHeight;
|
|
87
|
+
x = x * pixelRatio
|
|
88
|
+
y = y * pixelRatio
|
|
89
|
+
}
|
|
90
|
+
// #endif
|
|
91
|
+
const params = {
|
|
92
|
+
...options,
|
|
93
|
+
canvasId,
|
|
94
|
+
id: canvasId,
|
|
95
|
+
// #ifdef MP-ALIPAY
|
|
96
|
+
x,
|
|
97
|
+
y,
|
|
98
|
+
width,
|
|
99
|
+
height,
|
|
100
|
+
destWidth,
|
|
101
|
+
destHeight,
|
|
102
|
+
// #endif
|
|
103
|
+
canvas,
|
|
104
|
+
success: (res) => {
|
|
105
|
+
resolve(res.tempFilePath)
|
|
106
|
+
},
|
|
107
|
+
fail: (err) => {
|
|
108
|
+
reject(err)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if(canvas && canvas.toTempFilePath) {
|
|
112
|
+
canvas.toTempFilePath(params)
|
|
113
|
+
} else {
|
|
114
|
+
uni.canvasToTempFilePath(params, context)
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
styles: String,
|
|
3
|
+
disableScroll: {
|
|
4
|
+
type: Boolean,
|
|
5
|
+
default: true
|
|
6
|
+
},
|
|
7
|
+
type: {
|
|
8
|
+
type: String,
|
|
9
|
+
default: '2d'
|
|
10
|
+
},
|
|
11
|
+
// 画笔颜色
|
|
12
|
+
penColor: {
|
|
13
|
+
type: String,
|
|
14
|
+
default: 'black'
|
|
15
|
+
},
|
|
16
|
+
penSize: {
|
|
17
|
+
type: Number,
|
|
18
|
+
default: 2
|
|
19
|
+
},
|
|
20
|
+
// 画板背景颜色
|
|
21
|
+
backgroundColor: String,
|
|
22
|
+
// 笔锋
|
|
23
|
+
openSmooth: Boolean,
|
|
24
|
+
// 画笔最小值
|
|
25
|
+
minLineWidth: {
|
|
26
|
+
type: Number,
|
|
27
|
+
default: 2
|
|
28
|
+
},
|
|
29
|
+
// 画笔最大值
|
|
30
|
+
maxLineWidth: {
|
|
31
|
+
type: Number,
|
|
32
|
+
default: 6
|
|
33
|
+
},
|
|
34
|
+
// 画笔达到最小宽度所需最小速度(px/ms),取值范围1.0-10.0,值越小,画笔越容易变细,笔锋效果会比较明显,可以自行调整查看效果,选出自己满意的值。
|
|
35
|
+
minSpeed: {
|
|
36
|
+
type: Number,
|
|
37
|
+
default: 1.5
|
|
38
|
+
},
|
|
39
|
+
// 相邻两线宽度增(减)量最大百分比,取值范围1-100,为了达到笔锋效果,画笔宽度会随画笔速度而改变,如果相邻两线宽度差太大,过渡效果就会很突兀,使用maxWidthDiffRate限制宽度差,让过渡效果更自然。可以自行调整查看效果,选出自己满意的值。
|
|
40
|
+
maxWidthDiffRate: {
|
|
41
|
+
type: Number,
|
|
42
|
+
default: 20
|
|
43
|
+
},
|
|
44
|
+
// 限制历史记录数,即最大可撤销数,传入0则关闭历史记录功能
|
|
45
|
+
maxHistoryLength: {
|
|
46
|
+
type: Number,
|
|
47
|
+
default: 20
|
|
48
|
+
},
|
|
49
|
+
beforeDelay: {
|
|
50
|
+
type: Number,
|
|
51
|
+
default: 10
|
|
52
|
+
},
|
|
53
|
+
landscape: {
|
|
54
|
+
type: Boolean
|
|
55
|
+
},
|
|
56
|
+
boundingBox: {
|
|
57
|
+
type: Boolean
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// #ifdef APP-VUE
|
|
2
|
+
// import { Signature } from '@signature'
|
|
3
|
+
import { Signature } from './signature'
|
|
4
|
+
export default {
|
|
5
|
+
data() {
|
|
6
|
+
return {
|
|
7
|
+
canvasid: null,
|
|
8
|
+
signature: null,
|
|
9
|
+
observer: null,
|
|
10
|
+
options: {},
|
|
11
|
+
saveCount: 0,
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
mounted() {
|
|
15
|
+
this.$nextTick(this.init)
|
|
16
|
+
},
|
|
17
|
+
methods: {
|
|
18
|
+
init() {
|
|
19
|
+
const el = this.$refs.limeSignature||this.$ownerInstance.$el;
|
|
20
|
+
const canvas = document.createElement('canvas')
|
|
21
|
+
canvas.style = 'width: 100%; height: 100%;'
|
|
22
|
+
el.appendChild(canvas)
|
|
23
|
+
this.signature = new Signature({
|
|
24
|
+
el: canvas
|
|
25
|
+
})
|
|
26
|
+
this.signature.pen.setOption(this.options)
|
|
27
|
+
const width = this.signature.canvas.get('width')
|
|
28
|
+
const height = this.signature.canvas.get('height')
|
|
29
|
+
|
|
30
|
+
this.emit({
|
|
31
|
+
changeSize: {
|
|
32
|
+
width,
|
|
33
|
+
height
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
},
|
|
37
|
+
undo(v) {
|
|
38
|
+
if (v && this.signature) {
|
|
39
|
+
this.signature.undo()
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
clear(v) {
|
|
43
|
+
if (v && this.signature) {
|
|
44
|
+
this.signature.clear()
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
save(param) {
|
|
48
|
+
let {fileType = 'png', quality = 1, n} = JSON.parse(param)
|
|
49
|
+
const type = `image/${fileType}`.replace(/jpg/, 'jpeg');
|
|
50
|
+
if (n !== this.saveCount) {
|
|
51
|
+
this.saveCount = n;
|
|
52
|
+
const {backgroundColor, landscape, boundingBox} = this.options
|
|
53
|
+
const flag = landscape || backgroundColor || boundingBox
|
|
54
|
+
console.log('type', type)
|
|
55
|
+
console.log('flag', flag)
|
|
56
|
+
const image = this.signature.canvas.get('el').toDataURL(!flag && type, !flag && quality)
|
|
57
|
+
console.log('image', image.length)
|
|
58
|
+
if (flag) {
|
|
59
|
+
const canvas = document.createElement('canvas')
|
|
60
|
+
const pixelRatio = this.signature.canvas.get('pixelRatio')
|
|
61
|
+
let width = this.signature.canvas.get('width')
|
|
62
|
+
let height = this.signature.canvas.get('height')
|
|
63
|
+
let x = 0
|
|
64
|
+
let y = 0
|
|
65
|
+
|
|
66
|
+
const next = () => {
|
|
67
|
+
const size = [width, height]
|
|
68
|
+
console.log('size width', width)
|
|
69
|
+
console.log('size height', height)
|
|
70
|
+
console.log('size pixelRatio', pixelRatio)
|
|
71
|
+
if(landscape) {size.reverse()}
|
|
72
|
+
canvas.width = size[0] * pixelRatio
|
|
73
|
+
canvas.height = size[1] * pixelRatio
|
|
74
|
+
const param = [x, y, width, height, 0 , 0, width, height].map(item => item * pixelRatio)
|
|
75
|
+
const context = canvas.getContext('2d')
|
|
76
|
+
// context.scale(pixelRatio, pixelRatio)
|
|
77
|
+
if (landscape) {
|
|
78
|
+
context.translate(0, width * pixelRatio)
|
|
79
|
+
context.rotate(-Math.PI / 2)
|
|
80
|
+
}
|
|
81
|
+
console.log('backgroundColor', backgroundColor)
|
|
82
|
+
if (backgroundColor) {
|
|
83
|
+
context.fillStyle = backgroundColor
|
|
84
|
+
context.fillRect(0, 0, width * pixelRatio, height * pixelRatio)
|
|
85
|
+
}
|
|
86
|
+
// param
|
|
87
|
+
context.drawImage(this.signature.canvas.get('el'), ...param)
|
|
88
|
+
this.emit({
|
|
89
|
+
save: canvas.toDataURL(type, quality)
|
|
90
|
+
})
|
|
91
|
+
canvas.remove()
|
|
92
|
+
}
|
|
93
|
+
if(boundingBox) {
|
|
94
|
+
const res = this.signature.getContentBoundingBox()
|
|
95
|
+
width = res.width
|
|
96
|
+
height = res.height
|
|
97
|
+
x = res.startX
|
|
98
|
+
y = res.startY
|
|
99
|
+
next()
|
|
100
|
+
} else {
|
|
101
|
+
next()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
} else {
|
|
105
|
+
this.emit({
|
|
106
|
+
save: image
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
isEmpty(v) {
|
|
112
|
+
if (v && this.signature) {
|
|
113
|
+
const isEmpty = this.signature.isEmpty()
|
|
114
|
+
this.emit({
|
|
115
|
+
isEmpty
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
emit(event) {
|
|
120
|
+
this.$ownerInstance.callMethod('onMessage', {
|
|
121
|
+
detail: {
|
|
122
|
+
data: [{
|
|
123
|
+
event
|
|
124
|
+
}]
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
},
|
|
128
|
+
update(v) {
|
|
129
|
+
if (v) {
|
|
130
|
+
if (this.signature) {
|
|
131
|
+
this.options = v
|
|
132
|
+
this.signature.pen.setOption(v)
|
|
133
|
+
} else {
|
|
134
|
+
this.options = v
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// #endif
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,i)}return n}function e(e){for(var n=1;arguments.length>n;n++){var i=null!=arguments[n]?arguments[n]:{};n%2?t(Object(i),!0).forEach((function(t){a(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):t(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){for(var n=0;e.length>n;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function r(t,e,n){return e&&o(t.prototype,e),n&&o(t,n),Object.defineProperty(t,"prototype",{writable:!1}),t}function a(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function s(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&h(t,e)}function u(t){return u=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)},u(t)}function h(t,e){return h=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t},h(t,e)}function c(t,e){if(e&&("object"==typeof e||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t)}function l(t){var e=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}();return function(){var n,i=u(t);if(e){var o=u(this).constructor;n=Reflect.construct(i,arguments,o)}else n=i.apply(this,arguments);return c(this,n)}}var v=function(t){var e=n(t);return null!==t&&"object"===e||"function"===e},f={}.toString,d=function(t,e){return f.call(t)==="[object "+e+"]"},y=function(t){return d(t,"String")},p=function(t){return d(t,"Number")},g=function(t){return d(t,"Function")},m=function(){function t(){i(this,t),this.__events=void 0,this.__events={}}return r(t,[{key:"on",value:function(t,e){if(t&&e){var n=this.__events[t]||[];n.push(e),this.__events[t]=n}}},{key:"emit",value:function(t,e){var n=this;if(v(t)&&(t=(e=t)&&e.type),t){var i=this.__events[t];i&&i.length&&i.forEach((function(t){t.call(n,e)}))}}},{key:"off",value:function(t,e){var n=this.__events,i=n[t];if(i&&i.length)if(e)for(var o=0,r=i.length;r>o;o++)i[o]===e&&(i.splice(o,1),o--);else delete n[t]}},{key:"getEvents",value:function(){return this.__events}}]),t}(),x=function(t){s(n,m);var e=l(n);function n(t,o){var r;return i(this,n),(r=e.call(this)).context=void 0,r.canvas=void 0,r.attrs=void 0,r.isCanvasElement=void 0,r.context=t,r.canvas=o.canvas||t.canvas||{width:o.width||0,height:o.height||0},r.attrs=o||{},r.isCanvasElement=!0,r}return r(n,[{key:"width",get:function(){return this.canvas.width},set:function(t){this.canvas.width=t}},{key:"height",get:function(){return this.canvas.height},set:function(t){this.canvas.height=t}},{key:"getContext",value:function(){return this.context}},{key:"getBoundingClientRect",value:function(){var t=this.attrs||{},e=t.top,n=t.right,i=t.width,o=t.height,r=t.left,a=t.bottom;return{top:void 0===e?0:e,width:void 0===i?0:i,right:void 0===n?0:n,height:void 0===o?0:o,bottom:void 0===a?0:a,left:void 0===r?0:r}}},{key:"setAttribute",value:function(t,e){this.attrs[t]=e}},{key:"addEventListener",value:function(t,e){this.on(t,e)}},{key:"removeEventListener",value:function(t,e){this.off(t,e)}},{key:"dispatchEvent",value:function(t,e){this.emit(t,e)}}]),n}();var w=function(t,e){return t?function(t){if(!t)return!1;if(1!==t.nodeType||!t.nodeName||"canvas"!==t.nodeName.toLowerCase())return!1;var e=!1;try{t.addEventListener("eventTest",(function(){e=!0})),t.dispatchEvent(new Event("eventTest"))}catch(t){e=!1}return e}(t.canvas)?t.canvas:new x(t,e):null};function b(t,e){try{return t.currentStyle?t.currentStyle[e]:document.defaultView&&document.defaultView.getComputedStyle(t,null).getPropertyValue(e)}catch(t){return{width:300,height:150}[e]}}function k(t,e){var n=e.get("el");if(!n)return t;var i=n.getBoundingClientRect(),o=i.top,r=void 0===o?0:o,a=i.left,s=void 0===a?0:a,u=parseFloat(b(n,"padding-left"))||0,h=parseFloat(b(n,"padding-top"))||0;return{x:t.x-s-u,y:t.y-r-h}}function _(t,e){var n=e.get("landscape");if(!n)return t;if(g(n))return n(t,e);var i=e.get("height");return{x:t.y,y:i-t.x}}var E=function(t,e){var n=t.touches;if(!n||!n.length)return[_(k({x:t.clientX,y:t.clientY},e),e)];n.length||(n=t.changedTouches||[]);for(var i=[],o=0,r=n.length;r>o;o++){var a=n[o],s=a.x,u=a.y,h=a.clientX,c=a.clientY,l=void 0;l=p(s)||p(u)?{x:s,y:u}:k({x:h,y:c},e),i.push(_(l,e))}return i},L=function(t,e){var n=e.x-t.x,i=e.y-t.y;return Math.abs(n)>Math.abs(i)?n>0?"right":"left":i>0?"down":"up"},M=function(t,e){var n=Math.abs(e.x-t.x),i=Math.abs(e.y-t.y);return Math.sqrt(n*n+i*i)},P=function(){function t(e){var n=this,o=e.canvas,r=e.el;i(this,t),this.processEvent=void 0,this.canvas=void 0,this.startTime=0,this.endTime=0,this.startPoints=null,this.startDistance=0,this.center=null,this.pressTimeout=void 0,this.eventType=null,this.direction=null,this.lastMoveTime=0,this.prevMovePoints=null,this.prevMoveTime=0,this.lastMovePoints=null,this.pinch=!1,this._click=function(t){var e=E(t,n.canvas);t.points=e,n.emitEvent("click",t)},this._start=function(t){var e,i,o=E(t,n.canvas);o&&(t.points=o,n.emitEvent("touchstart",t),n.reset(),n.startTime=Date.now(),n.startPoints=o,o.length>1?(n.startDistance=M(o[0],o[1]),n.center={x:(e=o[0]).x+((i=o[1]).x-e.x)/2,y:e.y+(i.y-e.y)/2}):n.pressTimeout=setTimeout((function(){var e="press",i="none";t.direction=i,n.emitStart(e,t),n.emitEvent(e,t),n.eventType=e,n.direction=i}),250))},this._move=function(t){var e=E(t,n.canvas);if(e){t.points=e,n.emitEvent("touchmove",t);var i=n.startPoints;if(i)if(e.length>1){var o=n.startDistance,r=M(e[0],e[1]);t.zoom=r/o,t.center=n.center,n.emitStart("pinch",t),n.emitEvent("pinch",t)}else{var a=e[0].x-i[0].x,s=e[0].y-i[0].y,u=n.direction||L(i[0],e[0]);n.direction=u;var h=n.getEventType(e);t.direction=u,t.deltaX=a,t.deltaY=s,n.emitStart(h,t),n.emitEvent(h,t);var c=n.lastMoveTime,l=Date.now();l-c>0&&(n.prevMoveTime=c,n.prevMovePoints=n.lastMovePoints,n.lastMoveTime=l,n.lastMovePoints=e)}}},this._end=function(t){var e=E(t,n.canvas);t.points=e,n.emitEnd(t),n.emitEvent("touchend",t);var i=n.lastMoveTime;if(100>Date.now()-i){var o=i-(n.prevMoveTime||n.startTime);if(o>0){var r=n.prevMovePoints||n.startPoints,a=n.lastMovePoints;if(!r||!a)return;var s=M(r[0],a[0])/o;s>.3&&(t.velocity=s,t.direction=L(r[0],a[0]),n.emitEvent("swipe",t))}}n.reset();var u=t.touches;u&&u.length>0&&n._start(t)},this._cancel=function(t){n.emitEvent("touchcancel",t),n.reset()},this.canvas=o,this.delegateEvent(r),this.processEvent={}}return r(t,[{key:"delegateEvent",value:function(t){t.addEventListener("click",this._click),t.addEventListener("touchstart",this._start),t.addEventListener("touchmove",this._move),t.addEventListener("touchend",this._end),t.addEventListener("touchcancel",this._cancel)}},{key:"emitEvent",value:function(t,e){this.canvas.emit(t,e)}},{key:"getEventType",value:function(t){var e,n=this.eventType,i=this.startTime,o=this.startPoints;if(n)return n;var r=this.canvas.__events.pan;if(r&&r.length){var a=Date.now();if(!o)return;e=a-i>250&&10>M(o[0],t[0])?"press":"pan"}else e="press";return this.eventType=e,e}},{key:"enable",value:function(t){this.processEvent[t]=!0}},{key:"isProcess",value:function(t){return this.processEvent[t]}},{key:"emitStart",value:function(t,e){this.isProcess(t)||(this.enable(t),this.emitEvent("".concat(t,"start"),e))}},{key:"emitEnd",value:function(t){}},{key:"clearPressTimeout",value:function(){this.pressTimeout&&(clearTimeout(this.pressTimeout),this.pressTimeout=null)}},{key:"reset",value:function(){this.clearPressTimeout(),this.startTime=0,this.startPoints=null,this.startDistance=0,this.direction=null,this.eventType=null,this.pinch=!1,this.prevMoveTime=0,this.prevMovePoints=null,this.lastMoveTime=0,this.lastMovePoints=null}}]),t}(),T=function(t){s(o,m);var e=l(o);function o(t){var n;i(this,o),(n=e.call(this))._attrs={},n._isWindow=void 0,n._attrs=Object.assign({},t),n._isWindow="undefined"!=typeof window,n._initPixelRatio(),n._initCanvas();return["createImage","toDataURL","requestAnimationFrame"].forEach((function(e){n._initAttrs(e,t.canvas||n.get("el"))})),n}return r(o,[{key:"get",value:function(t){return this._attrs[t]}},{key:"set",value:function(t,e){this._attrs[t]=e}},{key:"_initAttrs",value:function(t,e){var n=this;if(!this.get(t)){this.set(t,(function(){return e[t]?e[t].apply(e,arguments):n._isWindow?window[t]?(i=window)[t].apply(i,arguments):"createImage"==t?new Image:null:void 0;var i}))}}},{key:"_initCanvas",value:function(){var t,e,n=this.get("el"),i=this.get("context");if(!n&&!i)throw Error("请指定 id、el 或 context!");t=n?y(n)?(e=n)?document.getElementById(e):null:n:w(i,this._attrs),i&&t&&!t.getContext&&(t.getContext=function(){return i});var o=this.get("width")||function(t){var e=b(t,"width");return"auto"===e&&(e=t.offsetWidth),parseFloat(e)}(t)||t.width,r=this.get("height")||function(t){var e=b(t,"height");return"auto"===e&&(e=t.offsetHeight),parseFloat(e)}(t)||t.height;this.set("canvas",this),this.set("el",t),this.set("context",i||t.getContext("2d")),this.changeSize(o,r);var a=new P({canvas:this,el:t,parent:this.get("parent")});this.set("eventController",a)}},{key:"_initPixelRatio",value:function(){this.get("pixelRatio")||this.set("pixelRatio",window&&window.devicePixelRatio||1)}},{key:"changeSize",value:function(t,e){var i,o=this.get("pixelRatio"),r=this.get("el");(r.style&&(r.style.width=t+"px",r.style.height=e+"px"),(i=r)&&"object"===n(i)&&(1===i.nodeType&&i.nodeName||i.isCanvasElement))&&(r.width=t*o,r.height=e*o,1!==o&&this.get("context").scale(o,o));this.set("width",t),this.set("height",e)}},{key:"destroy",value:function(){if(!this.get("destroyed")){var t=this.get("el");t.width=0,t.height=0,this.clear(),this._attrs={},this.set("destroyed",!0)}}},{key:"clear",value:function(){}},{key:"isDestroyed",value:function(){return this.get("destroyed")}}]),o}();var S={penColor:"black",backgroundColor:"",openSmooth:!0,penSize:2,minLineWidth:2,maxLineWidth:6,minSpeed:1.5,maxWidthDiffRate:20,maxHistoryLength:20},D=null,O=function(){function t(e){var n=this;i(this,t),this.canAddHistory=!0,this.points=[],this.historyList=[],this.canvas=void 0,this._isEmpty=!0,this.active=!1,this.getLineWidth=function(t){var e=n.get("options"),i=e.minSpeed,o=e.minLineWidth,r=n.getMaxLineWidth();return Math.min(Math.max(r-(r-o)*t/Math.max(Math.min(i,10),1),o),r)},this.drawTrapezoid=function(t,e,i,o){var r=n.get("context");r.beginPath(),r.moveTo(Number(t.x.toFixed(1)),Number(t.y.toFixed(1))),r.lineTo(Number(e.x.toFixed(1)),Number(e.y.toFixed(1))),r.lineTo(Number(i.x.toFixed(1)),Number(i.y.toFixed(1))),r.lineTo(Number(o.x.toFixed(1)),Number(o.y.toFixed(1))),r.fillStyle=n.get("options").penColor,r.fill(),r.draw&&r.draw(!0)},this.drawNoSmoothLine=function(t,e){e.lastX=t.x+.5*(e.x-t.x),e.lastY=t.y+.5*(e.y-t.y),"number"==typeof t.lastX&&n.drawCurveLine(t.lastX,t.lastY,t.x,t.y,e.lastX,e.lastY,n.getMaxLineWidth())},this.drawCurveLine=function(t,e,i,o,r,a,s){s=Number(s.toFixed(1));var u=n.get("context");u.lineWidth=s,u.beginPath(),u.moveTo(Number(t.toFixed(1)),Number(e.toFixed(1))),u.quadraticCurveTo(Number(i.toFixed(1)),Number(o.toFixed(1)),Number(r.toFixed(1)),Number(a.toFixed(1))),u.stroke(),u.draw&&u.draw(!0)},this.getRadianData=function(t,e,n,i){var o=n-t,r=i-e;if(0===o)return{val:0,pos:-1};if(0===r)return{val:0,pos:1};var a=Math.abs(Math.atan(r/o));return n>t&&e>i||t>n&&i>e?{val:a,pos:1}:{val:a,pos:-1}},this.getRadianPoints=function(t,e,n,i){if(0===t.val)return 1===t.pos?[{x:e,y:n+i},{x:e,y:n-i}]:[{y:n,x:e+i},{y:n,x:e-i}];var o=Math.sin(t.val)*i,r=Math.cos(t.val)*i;return 1===t.pos?[{x:e+o,y:n+r},{x:e-o,y:n-r}]:[{x:e+o,y:n-r},{x:e-o,y:n+r}]},this.drawSmoothLine=function(t,e){var i=e.x-t.x,o=e.y-t.y;if(Math.abs(i)+Math.abs(o)>2?(e.lastX1=t.x+.3*i,e.lastY1=t.y+.3*o,e.lastX2=t.x+.7*i,e.lastY2=t.y+.7*o):(e.lastX1=e.lastX2=t.x+.5*i,e.lastY1=e.lastY2=t.y+.5*o),e.perLineWidth=(t.lineWidth+e.lineWidth)/2,"number"==typeof t.lastX1){if(n.drawCurveLine(t.lastX2,t.lastY2,t.x,t.y,e.lastX1,e.lastY1,e.perLineWidth),t.isFirstPoint)return;if(t.lastX1===t.lastX2&&t.lastY1===t.lastY2)return;var r=n.getRadianData(t.lastX1,t.lastY1,t.lastX2,t.lastY2),a=n.getRadianPoints(r,t.lastX1,t.lastY1,t.perLineWidth/2),s=n.getRadianPoints(r,t.lastX2,t.lastY2,e.perLineWidth/2);n.drawTrapezoid(a[0],s[0],s[1],a[1])}else e.isFirstPoint=!0},this.addHistory=function(){var t=n.get("options").maxHistoryLength;if(t&&n.canAddHistory)if(n.canAddHistory=!1,n.get("createImage")){var e=null;e=n.get("createImage")();var i=n.get("toDataURL")&&n.get("toDataURL")();y(i)?e.src=i:i.then((function(t){e.src=t})),e.onload=function(){var i=D;D=e,n.historyList.push(i),n.historyList=n.historyList.slice(-t)}}else n.historyList.length++},this.drawByImage=function(t){var e=n.get("context"),i=n.get("width"),o=n.get("height");e.clearRect(0,0,i,o);try{t&&e.drawImage(t,0,0,i,o),e.draw&&e.draw(!0)}catch(t){n.historyList.length=0}},this.isEmpty=function(){return n.get("options").maxHistoryLength>0?0===n.historyList.length:n._isEmpty},this.clear=function(){var t=n.get("context");t.clearRect(0,0,n.get("width"),n.get("height")),t.draw&&t.draw(),n._isEmpty=!0,D=null,n.historyList.length=0},this.undo=function(){if(0===n.get("options").maxHistoryLength&&n.clear(),n.get("createImage")&&n.historyList.length){var t=n.historyList.splice(-1)[0];n.drawByImage(t),0===n.historyList.length&&n.clear()}},this.canvas=e,this.canvas.set("pen",S),this.init()}return r(t,[{key:"getOption",value:function(){}},{key:"setOption",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e({},t),i=n.maxLineWidth;if(i&&t.penSize&&i==S.maxLineWidth){var o=Math.max(i,t.penSize);n.maxLineWidth=o}this.canvas.set("pen",Object.assign({},S,n))}},{key:"get",value:function(t){return this.canvas.get("options"==t?"pen":t)}},{key:"init",value:function(){var t=this;this.get("context").lineCap="round",this.canvas.on("touchstart",(function(e){return t.onDrawStart(e)})),this.canvas.on("touchmove",(function(e){return t.onDrawMove(e)})),this.canvas.on("touchend",(function(e){return t.onDrawEnd(e)}))}},{key:"drawBackground",value:function(){var t=this.get("context"),e=this.get("width"),n=this.get("height"),i=this.get("options"),o=i.backgroundColor,r=i.backgroundImage;o&&(t.fillStyle=o,t.fillRect(0,0,e,n),t.draw&&t.draw(!0)),r&&this.drawByImage(r)}},{key:"getContentBoundingBox",value:function(t){var e=this.get("pixelRatio"),n=this.get("width"),i=this.get("height"),o=this.get("el"),r="CANVAS"===o.nodeName,a=r?n:o.width,s=r?i:o.height;e=r?1:e;var u=function(n){for(var i=a,o=s,r=0,u=0,h=0;n.length>h;h+=4){if(n[h+3]>0){var c=h/4%a,l=Math.floor(h/4/a);i=Math.min(i,c),o=Math.min(o,l),r=Math.max(r,c),u=Math.max(u,l)}}var v={width:(r-i+1)/e,height:(u-o+1)/e,startX:i/e,startY:o/e};return t&&t(v),v};if("CANVAS"===o.nodeName){var h=document.createElement("canvas");h.width=n,h.height=i;var c=h.getContext("2d");c.drawImage(o,0,0,n,i);var l=c.getImageData(0,0,n,i).data;return u(l)}var f,d=this.get("context").getImageData(0,0,a,s);return v(f=d)&&g(f.then)&&g(f.catch)?(d.then((function(t){return u(t.data)})),null):u(d.data)}},{key:"remove",value:function(){var t=this;this.canvas.off("touchstart",(function(e){return t.onDrawStart(e)})),this.canvas.off("touchmove",(function(e){return t.onDrawMove(e)})),this.canvas.off("touchend",(function(e){return t.onDrawEnd(e)}))}},{key:"disableScroll",value:function(t){t.preventDefault&&this.get("options").disableScroll&&t.preventDefault()}},{key:"onDrawStart",value:function(t){this.disableScroll(t);var e=t.points;if(this.active){this.canAddHistory=!0,this.get("context").strokeStyle=this.get("options").penColor;var n=e[0];this.initPoint(n.x,n.y)}}},{key:"onDrawMove",value:function(t){if(this.disableScroll(t),this.active){var e=t.points[0];this.initPoint(e.x,e.y),this.onDraw()}}},{key:"onDrawEnd",value:function(t){this.active&&(this.addHistory(),this.canAddHistory=!0,this.points=[])}},{key:"onDraw",value:function(){var t=this,e=this.get("context");if(this.points.length>=2){e.lineWidth=this.get("options").penSize||2;var n=this.points.slice(-1)[0],i=this.points.slice(-2,-1)[0],o=function(){t._isEmpty=!1,t.get("options").openSmooth?t.drawSmoothLine(i,n):t.drawNoSmoothLine(i,n)},r=this.get("el").canvas;r&&r.requestAnimationFrame?r.requestAnimationFrame((function(){return o()})):"function"==typeof requestAnimationFrame?requestAnimationFrame((function(){return o()})):o()}}},{key:"getMaxLineWidth",value:function(){var t=this.get("options");return Math.min(t.penSize,t.maxLineWidth)}},{key:"initPoint",value:function(t,e){var n={x:t,y:e,t:Date.now()},i=this.points.slice(-1)[0];if(!i||i.t!==n.t&&(i.x!==t||i.y!==e)){if(this.get("options").openSmooth&&i){var o=this.points.slice(-2,-1)[0];if(n.distance=Math.sqrt(Math.pow(n.x-i.x,2)+Math.pow(n.y-i.y,2)),n.speed=n.distance/(n.t-i.t||.1),n.lineWidth=this.getLineWidth(n.speed),o&&o.lineWidth&&i.lineWidth){var r=(n.lineWidth-i.lineWidth)/i.lineWidth,a=this.get("options").maxWidthDiffRate/100;if(a=a>1?1:.01>a?.01:a,Math.abs(r)>a)n.lineWidth=i.lineWidth*(1+(r>0?a:-a))}}this.points.push(n),this.points=this.points.slice(-3)}}}]),t}(),W=function(){function t(e){i(this,t),this.canvas=void 0,this._ee=void 0,this.pen=void 0;var n=new T(e);n.set("parent",this),this.canvas=n,this._ee=new m,this.pen=new O(n),this.init()}return r(t,[{key:"init",value:function(){this.pen.active=!0}},{key:"destroy",value:function(){this.canvas.destroy()}},{key:"clear",value:function(){this.pen.clear()}},{key:"undo",value:function(){this.pen.undo()}},{key:"save",value:function(){}},{key:"getContentBoundingBox",value:function(t){return this.pen.getContentBoundingBox(t)}},{key:"isEmpty",value:function(){return this.pen.isEmpty()}},{key:"on",value:function(t,e){this._ee.on(t,e)}},{key:"emit",value:function(t,e){this._ee.emit(t,e)}},{key:"off",value:function(t,e){this._ee.off(t,e)}}]),t}();export default W;export{W as Signature};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
export function compareVersion(v1, v2) {
|
|
2
|
+
v1 = v1.split('.')
|
|
3
|
+
v2 = v2.split('.')
|
|
4
|
+
const len = Math.max(v1.length, v2.length)
|
|
5
|
+
while (v1.length < len) {
|
|
6
|
+
v1.push('0')
|
|
7
|
+
}
|
|
8
|
+
while (v2.length < len) {
|
|
9
|
+
v2.push('0')
|
|
10
|
+
}
|
|
11
|
+
for (let i = 0; i < len; i++) {
|
|
12
|
+
const num1 = parseInt(v1[i], 10)
|
|
13
|
+
const num2 = parseInt(v2[i], 10)
|
|
14
|
+
|
|
15
|
+
if (num1 > num2) {
|
|
16
|
+
return 1
|
|
17
|
+
} else if (num1 < num2) {
|
|
18
|
+
return -1
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return 0
|
|
22
|
+
}
|
|
23
|
+
let {platform, SDKVersion} = uni.getSystemInfoSync()
|
|
24
|
+
function gte(version) {
|
|
25
|
+
// #ifdef MP-ALIPAY
|
|
26
|
+
SDKVersion = my.SDKVersion
|
|
27
|
+
// #endif
|
|
28
|
+
return compareVersion(SDKVersion, version) >= 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const isPC = /windows|mac/.test(platform)
|
|
32
|
+
export function canIUseCanvas2d() {
|
|
33
|
+
// #ifdef MP-WEIXIN
|
|
34
|
+
return gte('2.9.0');
|
|
35
|
+
// #endif
|
|
36
|
+
// #ifdef MP-ALIPAY
|
|
37
|
+
return gte('2.7.0');
|
|
38
|
+
// #endif
|
|
39
|
+
// #ifdef MP-TOUTIAO
|
|
40
|
+
return gte('1.78.0');
|
|
41
|
+
// #endif
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
export const wrapEvent = (e) => {
|
|
47
|
+
if (!e) return;
|
|
48
|
+
if (!e.preventDefault) {
|
|
49
|
+
e.preventDefault = function() {};
|
|
50
|
+
}
|
|
51
|
+
return e;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const requestAnimationFrame = (cb) => {
|
|
55
|
+
setTimeout(cb, 30)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// #ifdef MP
|
|
59
|
+
export const prefix = () => {
|
|
60
|
+
// #ifdef MP-TOUTIAO
|
|
61
|
+
return tt
|
|
62
|
+
// #endif
|
|
63
|
+
// #ifdef MP-WEIXIN
|
|
64
|
+
return wx
|
|
65
|
+
// #endif
|
|
66
|
+
// #ifdef MP-BAIDU
|
|
67
|
+
return swan
|
|
68
|
+
// #endif
|
|
69
|
+
// #ifdef MP-ALIPAY
|
|
70
|
+
return my
|
|
71
|
+
// #endif
|
|
72
|
+
// #ifdef MP-QQ
|
|
73
|
+
return qq
|
|
74
|
+
// #endif
|
|
75
|
+
// #ifdef MP-360
|
|
76
|
+
return qh
|
|
77
|
+
// #endif
|
|
78
|
+
}
|
|
79
|
+
// #endif
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* base64转路径
|
|
83
|
+
* @param {Object} base64
|
|
84
|
+
*/
|
|
85
|
+
export function base64ToPath(base64) {
|
|
86
|
+
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
// #ifdef MP
|
|
89
|
+
const p = prefix()
|
|
90
|
+
const fs = p.getFileSystemManager()
|
|
91
|
+
//自定义文件名
|
|
92
|
+
if (!format) {
|
|
93
|
+
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
|
94
|
+
}
|
|
95
|
+
const time = new Date().getTime();
|
|
96
|
+
const filePath = `${p.env.USER_DATA_PATH}/${time}.${format}`;
|
|
97
|
+
fs.writeFile({
|
|
98
|
+
filePath,
|
|
99
|
+
data: base64.split(',')[1],
|
|
100
|
+
encoding: 'base64',
|
|
101
|
+
success() {
|
|
102
|
+
resolve(filePath)
|
|
103
|
+
},
|
|
104
|
+
fail(err) {
|
|
105
|
+
reject(err)
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
// #endif
|
|
109
|
+
// #ifdef APP-PLUS
|
|
110
|
+
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
|
111
|
+
bitmap.loadBase64Data(base64, () => {
|
|
112
|
+
if (!format) {
|
|
113
|
+
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
|
114
|
+
}
|
|
115
|
+
const time = new Date().getTime();
|
|
116
|
+
const filePath = `_doc/uniapp_temp/${time}.${format}`
|
|
117
|
+
bitmap.save(filePath, {},
|
|
118
|
+
() => {
|
|
119
|
+
bitmap.clear()
|
|
120
|
+
resolve(filePath)
|
|
121
|
+
},
|
|
122
|
+
(error) => {
|
|
123
|
+
bitmap.clear()
|
|
124
|
+
reject(error)
|
|
125
|
+
})
|
|
126
|
+
}, (error) => {
|
|
127
|
+
bitmap.clear()
|
|
128
|
+
reject(error)
|
|
129
|
+
})
|
|
130
|
+
// #endif
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
export function sleep(delay) {
|
|
136
|
+
return new Promise(resolve => setTimeout(resolve, delay))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function getRect(selector, options = {}) {
|
|
140
|
+
const typeDefault = 'boundingClientRect'
|
|
141
|
+
const { context, type = typeDefault} = options
|
|
142
|
+
return new Promise((resolve, reject) => {
|
|
143
|
+
const dom = uni.createSelectorQuery().in(context).select(selector);
|
|
144
|
+
const result = (rect) => {
|
|
145
|
+
if(rect) {
|
|
146
|
+
resolve(rect)
|
|
147
|
+
} else {
|
|
148
|
+
reject()
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if(type == typeDefault) {
|
|
152
|
+
dom[type](result).exec()
|
|
153
|
+
} else {
|
|
154
|
+
dom[type]({
|
|
155
|
+
node: true,
|
|
156
|
+
size: true,
|
|
157
|
+
rect: true
|
|
158
|
+
}, result).exec()
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
};
|