Smooth-Signature H5 viene con firma de escritura a mano con punta de lápiz y admite uso de PC/móvil
Biblioteca de gestión multiestado de miniprogramas de minitiendas, compatible con el uso de miniprogramas multiplataforma
Afectados por la epidemia, los procesos sin papel y los contratos electrónicos se han vuelto populares, la demanda de firmas electrónicas también ha seguido aumentando y la experiencia de la firma ha mejorado gradualmente, desde dibujar líneas en un simple lienzo al principio hasta perseguir líneas sedosas y redondas. , y luego requiere papel japonés. El efecto del borde del lápiz es el mismo que el de escribir en él, etc. Hay muchas bibliotecas de firmas de código abierto listas para usar en Internet. Entre ellas, el efecto de trazo de Signature_pad es mejor, pero aún encontrarás una sensación obvia de irregularidad al usarlo, así que usé mi tiempo libre para implementar otra solución basada en mi. propia comprensión Al mismo tiempo, también desarrollamos una versión del mini programa y la compartimos con los estudiantes necesitados.
npm install mini-smooth-signature
# 或
yarn add mini-smooth-signature
Admite miniprogramas WeChat/Alipay/DingTalk/QQ. El siguiente es el código de prueba para la plataforma DingTalk. Consulte los ejemplos de códigos de muestra de cada plataforma en otras plataformas. Puede consultar los ejemplos existentes para verificar su uso.
< view >
< canvas
id = " signature "
width = " {{width * scale}} "
height = " {{height * scale}} "
style = " width:{{width}}px;height:{{height}}px; "
disable-scroll = " {{true}} "
onTouchStart = " handleTouchStart "
onTouchMove = " handleTouchMove "
onTouchCancel = " handleTouchEnd "
onTouchEnd = " handleTouchEnd "
/>
</ view >
import Signature from 'mini-smooth-signature' ;
Page ( {
data : {
width : 320 ,
height : 200 ,
scale : 2 ,
} ,
onReady ( ) {
this . initSignature ( )
} ,
// 初始化
initSignature ( ) {
const ctx = dd . createCanvasContext ( 'signature' ) ;
this . signature = new Signature ( ctx , {
width : this . data . width ,
height : this . data . height ,
scale : this . data . scale ,
getImagePath : ( ) => {
return new Promise ( ( resolve ) => {
ctx . toTempFilePath ( {
success : res => resolve ( res . filePath ) ,
} )
} )
}
} ) ;
} ,
// 绑定touchstart事件
handleTouchStart ( e ) {
const pos = e . touches [ 0 ] ;
this . signature . onDrawStart ( pos . x , pos . y ) ;
} ,
// 绑定touchmove事件
handleTouchMove ( e ) {
const pos = e . touches [ 0 ] ;
this . signature . onDrawMove ( pos . x , pos . y ) ;
} ,
// 绑定touchend/touchcancel事件
handleTouchEnd ( ) {
this . signature . onDrawEnd ( ) ;
} ,
} ) ;
Todos los elementos de configuración son opcionales.
const signature = new Signature ( ctx , {
width : 300 ,
height : 600 ,
scale : 2 ,
minWidth : 4 ,
maxWidth : 10 ,
color : '#1890ff' ,
bgColor : '#efefef' ,
} ) ;
opciones.ancho
El ancho del lienzo realmente representado en la página (px)
number
opciones.altura
La altura del lienzo realmente representado en la página (px)
number
opciones.escala
Zoom de lienzo
number
opciones.color
color del pincel
string
opciones.bgColor
Color de fondo del lienzo
string
opciones.getImagePath
Función de promesa que genera imágenes temporales para guardar el historial. Si este elemento no está configurado, la función deshacer no está disponible.
promise
opciones.toDataURL
Generar función de imagen base64
function
opciones.requestAnimationFrame
Se ejecuta la próxima vez que se vuelve a dibujar. Se utiliza para mejorar el rendimiento de la pintura y reducir el retraso y la falta de suavidad.
function
opciones.openSmooth
Si se debe habilitar el efecto de borde del lápiz, habilitado de forma predeterminada
boolean
opciones.minAncho
El ancho mínimo del pincel (px), el ancho mínimo del pincel cuando la punta del lápiz está encendida
number
opciones.maxWidth
El ancho máximo del pincel (px), el ancho máximo del pincel cuando el borde del pincel está activado o el ancho normal del pincel cuando el borde del pincel no está activado
number
opciones.minVelocidad
La velocidad mínima (px/ms) requerida para que el pincel alcance el ancho mínimo. El rango de valores es 1,0-10,0. Cuanto menor sea el valor, más fácil será que el pincel se vuelva más delgado y el efecto de la punta del pincel será mayor. obvio Puede ajustar el efecto de visualización usted mismo y elegir un valor con el que esté satisfecho.
number
opciones.maxWidthDiffRate
El porcentaje máximo de aumento (disminución) en el ancho de dos líneas adyacentes. El rango de valores es de 1 a 100. Para lograr el efecto de trazo, el ancho del pincel cambiará con la velocidad del pincel si la diferencia de ancho entre dos líneas adyacentes es. demasiado grande, el efecto de transición será abrupto. Utilice maxWidthDiffRate para limitar la diferencia de ancho y hacer que el efecto de transición sea más natural. Puede ajustar el efecto de visualización usted mismo y elegir un valor con el que esté satisfecho.
number
opciones.maxHistoryLength
Limite el número de registros del historial, es decir, el número máximo que se puede deshacer. Pasar 0 desactivará la función de registro del historial.
number
// 画布上下文context
signature . ctx
// 清屏
signature . clear ( )
// 撤销,如果未配置getImagePath,则不可用
signature . undo ( )
// 获取base64图片,若未配置toDataURL,则不可用
signature . toDataURL ( )
// 是否为空
signature . isEmpty ( )
Normalmente escribimos en papel. Si miras de cerca, encontrarás que el grosor de los trazos es desigual. Esto se debe a la diferente fuerza de presión y velocidad de movimiento del bolígrafo durante el proceso de escritura. En los navegadores de computadoras y dispositivos móviles, aunque no podemos obtener la presión del tacto, podemos usar la velocidad del movimiento del pincel para lograr efectos de trazo desiguales, haciendo que la fuente se vea tan nítida como si estuviera escrita en papel. , el proceso de implementación específico se presenta a continuación (el código que se muestra a continuación es solo para facilitar la comprensión, no el código de implementación final).
Recopile las coordenadas de los puntos movidos escuchando el evento de movimiento del lienzo, registre la hora actual y luego guárdela en la matriz de puntos.
function onTouchMove ( x , y ) {
const point = { x , y , t : Date . now ( ) }
points . push ( point ) ;
} ;
Calcule la distancia entre los dos puntos a través de las coordenadas de los dos puntos y luego divídala por la diferencia de tiempo para obtener la velocidad de movimiento.
const distance = Math . sqrt ( Math . pow ( end . x - start . x , 2 ) + Math . pow ( end . y - start . y , 2 ) ) ;
const speed = distance / ( end . t - start . t ) ;
Obtenga la velocidad de movimiento entre dos puntos y luego calcule el ancho de la línea mediante un algoritmo simple, donde maxWidth, minWidth y minSpeed son elementos de configuración.
const addWidth = ( maxWidth - minWidth ) * speed / minSpeed ;
const lineWidth = Math . min ( Math . max ( maxWidth - addWidth , minWidth ) , maxWidth ) ;
Además, para evitar que la diferencia de ancho entre dos líneas adyacentes sea demasiado grande y provoque un efecto de transición abrupta, se deben establecer restricciones, donde maxWidthDiffRate es un elemento de configuración y preLineWidth es el ancho de la línea anterior.
const rate = ( lineWidth - preLineWidth ) / preLineWidth ;
const maxRate = maxWidthDiffRate / 100 ;
if ( Math . abs ( rate ) > maxRate ) {
const per = rate > 0 ? maxRate : - maxRate ;
lineWidth = preLineWidth * ( 1 + per ) ;
}
Ahora que sabes el ancho de la línea entre cada dos puntos, el siguiente paso es dibujar la línea. Para que las líneas parezcan redondeadas y la transición entre los grosores de las líneas sea más natural, promedié la línea entre dos puntos en tres segmentos, donde:
Comience a dibujar la línea, primero mire el primer segmento de la línea, porque el primer segmento de la línea se cruza con la línea anterior, para garantizar una transición suave entre las dos líneas, se utiliza una curva de Bézier cuadrática y el punto inicial point es el punto inicial del tercer segmento de la línea anterior (pre_x2, pre_y2).
ctx . lineWidth = lineWidth1
ctx . beginPath ( ) ;
ctx . moveTo ( pre_x2 , pre_y2 ) ;
ctx . quadraticCurveTo ( x0 , y0 , x1 , y1 ) ;
ctx . stroke ( ) ;
El segundo segmento de línea es la línea de transición que conecta el primer segmento y el tercer segmento. Dado que los anchos de línea del primer segmento y del tercer segmento son diferentes, el segundo segmento de la línea se rellena con un trapecio para hacer que el efecto de transición sea más intenso. natural.
ctx . beginPath ( ) ;
ctx . moveTo ( point1 . x , point1 . y ) ;
ctx . lineTo ( point2 . x , point2 . y ) ;
ctx . lineTo ( point3 . x , point3 . y ) ;
ctx . lineTo ( point4 . x , point4 . y ) ;
ctx . fill ( ) ;
Repita la operación anterior al dibujar la siguiente línea en el tercer párrafo.