【微信小程序canvas】實現(xiàn)小程序手寫板用戶簽名(附代碼)

【微信小程序canvas】實現(xiàn)小程序手寫板用戶簽名(附代碼)

工作中公司業(yè)務(wù)需要的微信小程序用戶簽字功能

先看效果圖:


demo

wxml

<view class="wrapper">
  <view class="handBtn">
    <button catchtap="retDraw" class="delBtn">重寫</button>
    <button catchtap="subCanvas" class="subBtn">完成</button> 
  </view>
  <view class="handCenter">
    <canvas class="handWriting" disable-scroll="true" bindtouchstart="uploadScaleStart" bindtouchmove="uploadScaleMove"
      bindtouchend="uploadScaleEnd" bindtap="mouseDown" canvas-id="handWriting">
    </canvas>
  </view>
  <view class="handRight">
    <view class="handTitle">手寫板</view>
  </view>
</view>

js

data

page({
    data: {
        canvasName: 'handWriting',
        ctx: '',
        canvasWidth: 0,
        canvasHeight: 0,
        transparent: 1, // 透明度
        selectColor: 'black',
        lineColor: '#1A1A1A', // 顏色
        lineSize: 1.5,  // 筆記倍數(shù)
        lineMin: 0.5,   // 最小筆畫半徑
        lineMax: 4,     // 最大筆畫半徑
        pressure: 1,     // 默認(rèn)壓力
        smoothness: 60,  //順滑度僵控,用60的距離來計算速度
        currentPoint: {},
        currentLine: [],  // 當(dāng)前線條
        firstTouch: true, // 第一次觸發(fā)
        radius: 1, //畫圓的半徑
        cutArea: { top: 0, right: 0, bottom: 0, left: 0 }, //裁剪區(qū)域
        bethelPoint: [],  //保存所有線條 生成的貝塞爾點勺远;
        lastPoint: 0,
        chirography: [], //筆跡
        currentChirography: {}, //當(dāng)前筆跡
        linePrack: [], //劃線軌跡 , 生成線條的實際點
    }
})

初始化

page({
  onLoad () {
    let canvasName = this.data.canvasName
    let ctx = wx.createCanvasContext(canvasName)
    this.setData({
      ctx: ctx
    })
    var query = wx.createSelectorQuery();
        query.select('.handCenter').boundingClientRect(rect => {query.select('.handCenter').boundingClientRect(rect => {
          this.setData({this.setData({
            canvasWidth: rect.width,canvasWidth: rect.width,
            canvasHeight: rect.heightcanvasHeight: rect.height
          })})
        }).exec(); }).exec();
      }, },
})

事件函數(shù)

筆跡開始

// 筆跡開始
  uploadScaleStart (e) {
    if (e.type != 'touchstart') return false;
    let ctx = this.data.ctx;
    ctx.setFillStyle(this.data.lineColor);  // 初始線條設(shè)置顏色
    ctx.setGlobalAlpha(this.data.transparent);  // 設(shè)置半透明
    let currentPoint = {
      x: e.touches[0].x,
      y: e.touches[0].y
    }
    let currentLine = this.data.currentLine;
    currentLine.unshift({
      time: new Date().getTime(),
      dis: 0,
      x: currentPoint.x,
      y: currentPoint.y
    })
    this.setData({
      currentPoint,
      // currentLine
    })
    if (this.data.firstTouch) {
      this.setData({
        cutArea: { top: currentPoint.y, right: currentPoint.x, bottom: currentPoint.y, left: currentPoint.x },
        firstTouch: false
      })
    }
    this.pointToLine(currentLine);
  },

筆跡移動

// 筆跡移動
  uploadScaleMove (e) {
    if (e.type != 'touchmove') return false;
    if (e.cancelable) {
      // 判斷默認(rèn)行為是否已經(jīng)被禁用
      if (!e.defaultPrevented) {
        e.preventDefault();
      }
    }
    let point = {
      x: e.touches[0].x,
      y: e.touches[0].y
    }

    //測試裁剪
    if (point.y < this.data.cutArea.top) {
      this.data.cutArea.top = point.y;
    }
    if (point.y < 0) this.data.cutArea.top = 0;

    if (point.x > this.data.cutArea.right) {
      this.data.cutArea.right = point.x;
    }
    if (this.data.canvasWidth - point.x <= 0) {
      this.data.cutArea.right = this.data.canvasWidth;
    }
    if (point.y > this.data.cutArea.bottom) {
      this.data.cutArea.bottom = point.y;
    }
    if (this.data.canvasHeight - point.y <= 0) {
      this.data.cutArea.bottom = this.data.canvasHeight;
    }
    if (point.x < this.data.cutArea.left) {
      this.data.cutArea.left = point.x;
    }
    if (point.x < 0) this.data.cutArea.left = 0;

    this.setData({
      lastPoint: this.data.currentPoint,
      currentPoint: point
    })
    let currentLine = this.data.currentLine
    currentLine.unshift({
      time: new Date().getTime(),
      dis: this.distance(this.data.currentPoint, this.data.lastPoint),
      x: point.x,
      y: point.y
    })
    // this.setData({
    //   currentLine
    // })
    this.pointToLine(currentLine);
  },

筆跡結(jié)束

// 筆跡結(jié)束
  uploadScaleEnd (e) {
    if (e.type != 'touchend') return 0;
    let point = {
      x: e.changedTouches[0].x,
      y: e.changedTouches[0].y
    }
    this.setData({
      lastPoint: this.data.currentPoint,
      currentPoint: point
    })
    let currentLine = this.data.currentLine
    currentLine.unshift({
      time: new Date().getTime(),
      dis: this.distance(this.data.currentPoint, this.data.lastPoint),
      x: point.x,
      y: point.y
    })
    // this.setData({
    //   currentLine
    // })
    if (currentLine.length > 2) {
      var info = (currentLine[0].time - currentLine[currentLine.length - 1].time) / currentLine.length;
      //$("#info").text(info.toFixed(2));
    }
    //一筆結(jié)束避凝,保存筆跡的坐標(biāo)點脾拆,清空毒嫡,當(dāng)前筆跡
    //增加判斷是否在手寫區(qū)域观腊;
    this.pointToLine(currentLine);
    var currentChirography = {
      lineSize: this.data.lineSize,
      lineColor: this.data.lineColor
    };
    var chirography = this.data.chirography
    chirography.unshift(currentChirography);
    this.setData({
      chirography
    })
    var linePrack = this.data.linePrack
    linePrack.unshift(this.data.currentLine);
    this.setData({
      linePrack,
      currentLine: []
    })
  },

wxss

page {
  background: #fbfbfb;
  height: auto;
  overflow: hidden;
}

.wrapper {
  width: 100%;
  height: 95vh;
  margin: 30rpx 0;
  overflow: hidden;
  display: flex;
  align-content: center;
  flex-direction: row;
  justify-content: center;
  font-size: 28rpx;
}

.handWriting {
  background: #fff;
  width: 100%;
  height: 95vh;
}

.handRight {
  display: inline-flex;
  align-items: center;
}

.handCenter {
  border: 4rpx dashed #e9e9e9;
  flex: 5;
  overflow: hidden;
  box-sizing: border-box;
}

.handTitle {
  transform: rotate(90deg);
  flex: 1;
  color: #666;
}

.handBtn button {
  font-size: 28rpx;
}

.handBtn {
  height: 95vh;
  display: inline-flex;
  flex-direction: column;
  justify-content: space-between;
  align-content: space-between;
  flex: 1;
}

.delBtn {
  position: absolute;
  top: 550rpx;
  left: 0rpx;
  transform: rotate(90deg);
  color: #666;
}

.delBtn image {
  position: absolute;
  top: 13rpx;
  left: 25rpx;
}

結(jié)語

詳細(xì)項目代碼handwriting-weapp(微信小程序原生canvas用戶簽字手寫板谎仲,后續(xù)更新計劃組件化浙垫、優(yōu)化渲染邏輯、增加功能郑诺,歡迎start 和 PR)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末夹姥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子辙诞,更是在濱河造成了極大的恐慌辙售,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件倘要,死亡現(xiàn)場離奇詭異圾亏,居然都是意外死亡,警方通過查閱死者的電腦和手機封拧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進(jìn)店門志鹃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泽西,你說我怎么就攤上這事曹铃。” “怎么了捧杉?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵陕见,是天一觀的道長秘血。 經(jīng)常有香客問我,道長评甜,這世上最難降的妖魔是什么灰粮? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮忍坷,結(jié)果婚禮上粘舟,老公的妹妹穿的比我還像新娘。我一直安慰自己佩研,他們只是感情好柑肴,可當(dāng)我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著旬薯,像睡著了一般晰骑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绊序,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天硕舆,我揣著相機與錄音,去河邊找鬼政模。 笑死岗宣,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的淋样。 我是一名探鬼主播耗式,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼趁猴!你這毒婦竟也來了刊咳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤儡司,失蹤者是張志新(化名)和其女友劉穎娱挨,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捕犬,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡跷坝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了碉碉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柴钻。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖垢粮,靈堂內(nèi)的尸體忽然破棺而出贴届,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布毫蚓,位于F島的核電站占键,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏元潘。R本人自食惡果不足惜畔乙,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望翩概。 院中可真熱鬧啸澡,春花似錦、人聲如沸氮帐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽上沐。三九已至,卻和暖如春楞艾,著一層夾襖步出監(jiān)牢的瞬間参咙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工硫眯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蕴侧,地道東北人。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓两入,卻偏偏與公主長得像净宵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子裹纳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,654評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載鏈接 注:本文轉(zhuǎn)載知乎上的回答 作者:初雪 鏈接:https://www.zhihu.com/question...
    pengshuangta閱讀 28,534評論 9 295
  • 自由寫作30天.轉(zhuǎn)型與蛻變第17篇 我們最大的恐懼择葡,不是我們的不足;我們最大的恐懼剃氧,是我們有無窮的力量敏储。是我們的光...
    真言臻宇閱讀 468評論 4 4
  • 你好 你好 再見 再見 簡潔和安溪是兩個普通而普通的女孩子,如果說有什么交集朋鞍,大概就是住在了同一所公寓同一層樓已添,成...
    子春緋閱讀 269評論 0 0
  • 我預(yù)感更舞,人生必經(jīng)的重大轉(zhuǎn)折,要在今年的年底發(fā)生了恨狈。 我閉上眼疏哗,感覺到我所做的每一件事,我動的每一個念,都會引發(fā)氣流...
    李砍柴閱讀 585評論 1 6