スムーズ署名 H5 にはペン先手書き署名が付属しており、PC/モバイルでの使用をサポートします。
mini-stores ミニ プログラム マルチステート管理ライブラリ、マルチプラットフォーム ミニ プログラムの使用をサポート
感染症の影響でペーパーレス化や電子契約が普及し、電子署名の需要も増え続け、当初はシンプルなキャンバスに線を描いていたものから、滑らかで丸い線を追求するなど、署名体験も徐々に向上してきました。 、そして和紙が必要です、ペンのエッジ効果はその上に書くのと同じです、など。インターネット上には既製のオープンソース署名ライブラリがたくさんありますが、その中でも、signature_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
オプション.bgColor
キャンバスの背景色
string
options.getImagePath
履歴を保存するための一時的な画像を生成する Promise 機能 この項目が設定されていない場合、Undo 機能は使用できません。
promise
options.toDataURL
Base64 イメージ関数を生成する
function
options.requestAnimationFrame
次回再描画が発生したときに実行されます。描画パフォーマンスを向上させ、遅れや滑らかさを軽減するために使用されます。
function
options.openSmooth
ペンエッジ効果を有効にするかどうか (デフォルトで有効)
boolean
options.minWidth
ブラシの最小幅(px)、ペン先をオンにしたときのブラシの最小幅
number
options.maxWidth
ブラシの最大幅(px)、ブラシエッジがオンになっているときのブラシの最大幅、またはブラシエッジがオンになっていないときのブラシの通常の幅
number
options.minSpeed
ブラシが最小幅に達するまでの最低速度 (px/ms) 値の範囲は 1.0 ~ 10.0 で、値が小さいほどブラシが細くなり、ブラシ先端の効果が大きくなります。当然のことですが、表示効果を自分で調整して、満足のいく値を選択できます。
number
options.maxWidthDiffRate
隣接する 2 つのラインの幅の最大増加 (減少) パーセント。ストローク効果を実現するために、ブラシの幅はブラシの速度に応じて変化します。大きすぎるとトランジション効果が突然になります。maxWidthDiffRate を使用して幅の差を制限し、トランジション効果をより自然にします。表示効果を自分で調整し、満足のいく値を選択できます。
number
options.maxHistoryLength
履歴記録の数、つまり元に戻せる最大数を制限します。0 を渡すと、履歴記録機能がオフになります。
number
// 画布上下文context
signature . ctx
// 清屏
signature . clear ( )
// 撤销,如果未配置getImagePath,则不可用
signature . undo ( )
// 获取base64图片,若未配置toDataURL,则不可用
signature . toDataURL ( )
// 是否为空
signature . isEmpty ( )
私たちは普段紙に文字を書いていますが、よく見ると筆の太さが不均一であることがわかります。これは、書く際のペンの押す力や移動速度の違いによるものです。コンピュータやモバイルのブラウザでは、タッチの圧力を取得することはできませんが、ブラシの動きの速度を利用して不均一なストローク効果を実現し、フォントを紙に書いているのと同じくらい鮮明に見せることができます。の具体的な実装プロセスを以下に紹介します (以下に示すコードは理解を容易にするためのものであり、最終的な実装コードではありません)。
キャンバス移動イベントをリッスンして、移動されたポイントの座標を収集し、現在時刻を記録して、それを Points 配列に保存します。
function onTouchMove ( x , y ) {
const point = { x , y , t : Date . now ( ) }
points . push ( point ) ;
} ;
2 点の座標から 2 点間の距離を計算し、それを時間差で割ると移動速度が求められます。
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 ) ;
2点間の移動速度を取得し、単純なアルゴリズムで線の幅を計算します。ここで、maxWidth、minWidth、minSpeedは設定項目です
const addWidth = ( maxWidth - minWidth ) * speed / minSpeed ;
const lineWidth = Math . min ( Math . max ( maxWidth - addWidth , minWidth ) , maxWidth ) ;
さらに、隣接する 2 つのライン間の幅の差が大きすぎて、突然の遷移効果が生じるのを防ぐために、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 点間の線の幅がわかったので、次のステップは線を描くことです。線を丸く見せ、線の太さの変化をより自然にするために、2 点間の線を 3 つのセグメントに平均化しました。
線の描画を開始し、まず線の最初のセグメントに注目します。線の最初のセグメントは前の線と交差するため、2 つの線の間のスムーズな移行を保証するために、2次ベジェ曲線が使用され、開始point は、前の行の 3 番目のセグメントの開始点 (pre_x2、pre_y2) です。
ctx . lineWidth = lineWidth1
ctx . beginPath ( ) ;
ctx . moveTo ( pre_x2 , pre_y2 ) ;
ctx . quadraticCurveTo ( x0 , y0 , x1 , y1 ) ;
ctx . stroke ( ) ;
2 番目の線分は、1 番目の線分と 3 番目の線分を接続する遷移線です。1 番目の線分と 3 番目の線分は線幅が異なるため、遷移効果を高めるために、2 番目の線分は台形で塗りつぶされます。自然。
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 ( ) ;
3 番目の段落の次の行を描画する場合も、上記の操作を繰り返します。