Smooth-signature H5에는 펜촉 필기 서명이 포함되어 있으며 PC/모바일 사용을 지원합니다.
미니 상점 미니 프로그램 다중 상태 관리 라이브러리, 다중 플랫폼 미니 프로그램 사용 지원
전염병의 영향으로 종이 없는 프로세스와 전자 계약이 대중화됨에 따라 전자 서명에 대한 수요도 지속적으로 증가했으며 처음에는 단순한 캔버스에 선을 그리는 것에서 부드럽고 둥근 선을 추구하는 것으로 서명 경험이 점차 향상되었습니다. , 일본 종이가 필요합니다. 펜 가장자리 효과는 위에 쓰는 것과 같습니다. 인터넷에는 기성 오픈 소스 서명 라이브러리가 많이 있습니다. 그중에서도 sign_pad 스트로크 효과가 더 좋지만 사용할 때 여전히 들쭉날쭉한 느낌이 들 수 있습니다. 그래서 나는 여가 시간을 활용하여 내 기반의 다른 솔루션을 구현했습니다. 동시에 미니 프로그램 버전도 개발해 도움이 필요한 학생들과 공유했습니다.
npm install mini-smooth-signature
# 或
yarn add mini-smooth-signature
WeChat/Alipay/DingTalk/QQ 미니 프로그램을 지원합니다. 다음은 DingTalk 플랫폼에 대한 테스트 코드입니다. 각 플랫폼의 샘플 코드는 예제를 참조하세요. 다른 플랫폼의 미니 프로그램은 기존 샘플을 참조하여 사용법을 확인할 수 있습니다.
< 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 ( ) ;
} ,
} ) ;
모든 구성 항목은 선택 사항입니다.
const signature = new Signature ( ctx , {
width : 300 ,
height : 600 ,
scale : 2 ,
minWidth : 4 ,
maxWidth : 10 ,
color : '#1890ff' ,
bgColor : '#efefef' ,
} ) ;
옵션.폭
페이지에 실제로 렌더링되는 캔버스의 너비(px)
number
옵션.높이
페이지에 실제로 렌더링되는 캔버스의 높이(px)
number
옵션.규모
캔버스 줌
number
옵션.색상
브러시 색상
string
옵션.bg색상
캔버스 배경색
string
options.getImagePath
이력 저장을 위한 임시 사진을 생성하는 Promise 기능입니다. 이 항목을 설정하지 않으면 실행 취소 기능을 사용할 수 없습니다.
promise
options.toDataURL
base64 이미지 함수 생성
function
options.requestAnimationFrame
다음에 다시 그리기가 발생할 때 실행됩니다. 페인팅 성능을 향상시키고 지연 및 부드러움을 줄이는 데 사용됩니다.
function
options.openSmooth
펜 가장자리 효과 활성화 여부(기본적으로 활성화됨)
boolean
옵션.최소 너비
브러시의 최소 너비(px), 펜촉을 켰을 때 브러시의 최소 너비
number
옵션.최대 너비
브러시의 최대 너비(px), 브러시 가장자리가 켜져 있을 때 브러시의 최대 너비 또는 브러시 가장자리가 켜지지 않을 때 브러시의 일반 너비
number
options.minSpeed
브러시가 최소 너비에 도달하는 데 필요한 최소 속도(px/ms)입니다. 값 범위는 1.0~10.0입니다. 값이 작을수록 브러시가 가늘어지기 쉽고 브러시 끝 효과가 커집니다. 시청 효과를 직접 조정하고 만족스러운 값을 선택할 수 있습니다.
number
options.maxWidthDiffRate
두 개의 인접한 선 너비의 최대 백분율 증가(감소)입니다. 값 범위는 1-100입니다. 스트로크 효과를 얻으려면 두 개의 인접한 선 사이의 너비 차이가 다음과 같은 경우 브러시 너비가 변경됩니다. 너무 크면 전환 효과가 갑자기 나타납니다. maxWidthDiffRate를 사용하여 너비 차이를 제한하여 전환 효과를 더 자연스럽게 만드세요. 시청 효과를 직접 조정하고 만족스러운 값을 선택할 수 있습니다.
number
options.maxHistoryLength
이력 기록 개수, 즉 취소할 수 있는 최대 개수를 제한합니다. 0을 전달하면 이력 기록 기능이 꺼집니다.
number
// 画布上下文context
signature . ctx
// 清屏
signature . clear ( )
// 撤销,如果未配置getImagePath,则不可用
signature . undo ( )
// 获取base64图片,若未配置toDataURL,则不可用
signature . toDataURL ( )
// 是否为空
signature . isEmpty ( )
우리는 보통 종이에 글을 쓰는데 자세히 보면 획의 굵기가 고르지 않다는 것을 알 수 있습니다. 이는 쓰는 과정에서 펜을 누르는 힘과 움직이는 속도가 다르기 때문입니다. 컴퓨터와 모바일 브라우저에서는 터치의 압력을 얻을 수 없지만 브러시 이동 속도를 사용하여 고르지 않은 획 효과를 얻을 수 있어 글꼴이 종이에 쓰는 것처럼 선명하게 보입니다. , 구체적인 구현 프로세스는 아래에 소개되어 있습니다. (아래 표시된 코드는 이해를 돕기 위한 것일 뿐 최종 구현 코드는 아닙니다.)
캔버스 이동 이벤트를 듣고 이동된 지점의 좌표를 수집하고 현재 시간을 기록한 후 포인트 배열에 저장합니다.
function onTouchMove ( x , y ) {
const point = { x , y , t : Date . now ( ) }
points . push ( point ) ;
} ;
두 점의 좌표를 통해 두 점 사이의 거리를 계산한 후 이를 시간차로 나누어 이동 속도를 구합니다.
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 ) ;
두 점 사이의 이동 속도를 구한 후, 간단한 알고리즘을 통해 선의 폭을 계산하는데, 여기서 maxWidth, minWidth, minSpeed는 구성 항목입니다.
const addWidth = ( maxWidth - minWidth ) * speed / minSpeed ;
const lineWidth = Math . min ( Math . max ( maxWidth - addWidth , minWidth ) , maxWidth ) ;
또한, 인접한 두 라인의 너비 차이가 너무 커져 갑작스러운 전환 효과가 발생하는 것을 방지하기 위해 maxWidthDiffRate가 구성 항목이고 preLineWidth가 이전 라인의 너비인 제한이 필요합니다.
const rate = ( lineWidth - preLineWidth ) / preLineWidth ;
const maxRate = maxWidthDiffRate / 100 ;
if ( Math . abs ( rate ) > maxRate ) {
const per = rate > 0 ? maxRate : - maxRate ;
lineWidth = preLineWidth * ( 1 + per ) ;
}
이제 모든 두 점 사이의 선 너비를 알았으므로 다음 단계는 선을 그리는 것입니다. 선을 둥글게 보이게 하고 선 두께 사이의 전환을 보다 자연스럽게 만들기 위해 두 점 사이의 선을 세 개의 세그먼트로 평균화했습니다.
선 그리기를 시작하고 먼저 선의 첫 번째 세그먼트를 살펴보세요. 선의 첫 번째 세그먼트가 이전 선과 교차하기 때문에 두 선 사이의 원활한 전환을 보장하기 위해 2차 베지어 곡선이 사용되며 시작 point는 이전 줄의 세 번째 세그먼트(pre_x2, pre_y2)의 시작점입니다.
ctx . lineWidth = lineWidth1
ctx . beginPath ( ) ;
ctx . moveTo ( pre_x2 , pre_y2 ) ;
ctx . quadraticCurveTo ( x0 , y0 , x1 , y1 ) ;
ctx . stroke ( ) ;
라인의 두 번째 세그먼트는 첫 번째 세그먼트와 세 번째 세그먼트를 연결하는 전환 선입니다. 첫 번째 세그먼트와 세 번째 세그먼트의 선 너비가 다르기 때문에 선의 두 번째 세그먼트를 사다리꼴로 채워 전환 효과를 더 만듭니다. 자연스러운.
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 ( ) ;
세 번째 단락에서 다음 줄을 그릴 때 위 작업을 반복합니다.