Canvas入門實戰之實現一個圖形驗證碼

2020-12-21 酷扯兒

本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫

本文主要介紹用canvas實現圖形驗證碼的一些思路以及如何用javascript面向對象的方式更友好的實現canvas的功能,關於canvas的一些基本使用方法和API我整理了一個思維導圖,大家感興趣的可以參考學習。

你將收穫

閉包的使用canvas常用api的使用javascript面向對象的實現方式實現一個canvas的圖形驗證碼的一般思路和常用算法設計思路

用canvas生成畫布用canvas畫幹擾線或躁點生成隨機不重複的n的字母用canvas繪製文字初始化和canvas點擊事件組件化封裝文末將附上組件封裝的源碼,歡迎大家隨時溝通交流。關於項目的打包,我將使用自己基於gulp4搭建的9012教你如何使用gulp4開發項目腳手架。

效果預覽

實現思路

我將按照上文中的設計思路的步驟一步步實現,首先我們先定義一個es5類:

function Gcode(el, option) {

this.el = typeof el === 'string' ? document.querySelector(el) : el;

this.option = option;

this.init();

}

其中init是用來初始化用的,參數el代表需要掛載的元素或元素id,option為傳入的可選項,稍後會在代碼中體現,通常這也是面向對象的常用套路。

繪製畫布

Gcode.prototype = {

constructor: Gcode,

init: function() {

if(this.el.getContext) {

isSupportCanvas = true;

var ctx = this.el.getContext('2d'),

// 設置畫布寬高

cw = this.el.width = this.option.width || 200,

ch = this.el.height = this.option.height || 40;

}

}

}

這裡我們在初始化方法中先定義一個canvas畫布,寬高為用戶自定義的寬高,默認為200*40。

繪製幹擾線

// 畫幹擾線

drawLine: function(ctx, lineNum, maxW, maxH) {

ctx.clearRect(0, 0, maxW, maxH);

for(var i=0; i < lineNum; i++) {

var dx1 = Math.random()* maxW,

dy1 = Math.random()* maxH,

dx2 = Math.random()* maxW,

dy2 = Math.random()* maxH;

ctx.strokeStyle = 'rgb(' + 255*Math.random() + ',' + 255*Math.random() + ',' + 255*Math.random() + ')';

ctx.beginPath();

ctx.moveTo(dx1, dy1);

ctx.lineTo(dx2, dy2);

ctx.stroke();

}

}

這裡我們對類Gcode定義原型方法drawLine,然後通過for循環繪製隨機位置的線條,為了讓canvas每次點擊能清空之前的幹擾線,我們使用clearRect來清除畫布。

生成隨機不重複的n個字符我們通過遞歸實現,如下==:

// 生成唯一文字

generateUniqueText: function(source, hasList, limit) {

var text = source[Math.floor(Math.random()*limit)];

if(hasList.indexOf(text) > -1) {

return this.generateUniqueText(source, hasList, limit)

}else {

return text

}

}

// 生成指定個數的隨機文字

randomText: function(len) {

var source = ['a', 'b', 'c', 'd', 'e',

'f', 'g', 'h', 'i', 'j',

'k', 'l', 'm', 'o', 'p',

'q', 'r', 's', 't', 'u',

'v', 'w', 'x', 'y', 'z'];

var result = [];

var sourceLen = source.length;

for(var i=0; i< len; i++) {

var text = this.generateUniqueText(source, result, sourceLen);

result.push(text)

}

return result.join('')

}

我們通過定義一個字母表,傳入生成的隨機字母的個數,配合generateUniqueText來實現生成唯一不重複的n個隨機字符。當然筆者認為這個方法並不優雅,你也可以使用uuid的方式或者更好的方式,歡迎隨時和筆者交流。

用canvas繪製文字

// 畫文字

drawText: function(ctx, text, maxH) {

var len = text.length;

for(var i=0; i < len; i++) {

var dx = 30 * Math.random() + 30* i,

dy = Math.random()* 5 + maxH/2;

ctx.fillStyle = 'rgb(' + 255*Math.random() + ',' + 255*Math.random() + ',' + 255*Math.random() + ')';

ctx.font = '30px Helvetica';

ctx.textBaseline = 'middle';

ctx.fillText(text[i], dx, dy);

}

},

這裡和上文畫線實現類似。就不做過多介紹了。

初始化和canvas點擊事件接下來我們看看完整的初始化代碼:

init: function() {

if(this.el.getContext) {

isSupportCanvas = true;

var ctx = this.el.getContext('2d'),

// 設置畫布寬高

cw = this.el.width = this.option.width || 200,

ch = this.el.height = this.option.height || 40,

textLen = this.option.textLen || 4,

lineNum = this.option.lineNum || 4;

var text = this.randomText(textLen);

this.onClick(ctx, textLen, lineNum, cw, ch);

this.drawLine(ctx, lineNum, cw, ch);

this.drawText(ctx, text, ch);

}

}

點擊事件主要是為了用戶點擊可以切換驗證碼:

onClick: function(ctx, textLen, lineNum, cw, ch) {

var _ = this;

this.el.addEventListener('click', function(){

text = _.randomText(textLen);

_.drawLine(ctx, lineNum, cw, ch);

_.drawText(ctx, text, ch);

}, false)

}

到此,一個完整的驗證碼組件實現完成,怎麼用呢?如下:

new Gcode('#canvas_code', {

lineNum: 6, // 可選

textLen: 4, // 可選

width: 200, // 可選

height: 50 // 可選

})

完整代碼如下,歡迎學習交流:

// canvas繪製圖形驗證碼

(function(){

function Gcode(el, option) {

this.el = typeof el === 'string' ? document.querySelector(el) : el;

this.option = option;

this.init();

}

Gcode.prototype = {

constructor: Gcode,

init: function() {

if(this.el.getContext) {

isSupportCanvas = true;

var ctx = this.el.getContext('2d'),

// 設置畫布寬高

cw = this.el.width = this.option.width || 200,

ch = this.el.height = this.option.height || 40,

textLen = this.option.textLen || 4,

lineNum = this.option.lineNum || 4;

var text = this.randomText(textLen);

this.onClick(ctx, textLen, lineNum, cw, ch);

this.drawLine(ctx, lineNum, cw, ch);

this.drawText(ctx, text, ch);

}

},

onClick: function(ctx, textLen, lineNum, cw, ch) {

var _ = this;

this.el.addEventListener('click', function(){

text = _.randomText(textLen);

_.drawLine(ctx, lineNum, cw, ch);

_.drawText(ctx, text, ch);

}, false)

},

// 畫幹擾線

drawLine: function(ctx, lineNum, maxW, maxH) {

ctx.clearRect(0, 0, maxW, maxH);

for(var i=0; i < lineNum; i++) {

var dx1 = Math.random()* maxW,

dy1 = Math.random()* maxH,

dx2 = Math.random()* maxW,

dy2 = Math.random()* maxH;

ctx.strokeStyle = 'rgb(' + 255*Math.random() + ',' + 255*Math.random() + ',' + 255*Math.random() + ')';

ctx.beginPath();

ctx.moveTo(dx1, dy1);

ctx.lineTo(dx2, dy2);

ctx.stroke();

}

},

// 畫文字

drawText: function(ctx, text, maxH) {

var len = text.length;

for(var i=0; i < len; i++) {

var dx = 30 * Math.random() + 30* i,

dy = Math.random()* 5 + maxH/2;

ctx.fillStyle = 'rgb(' + 255*Math.random() + ',' + 255*Math.random() + ',' + 255*Math.random() + ')';

ctx.font = '30px Helvetica';

ctx.textBaseline = 'middle';

ctx.fillText(text[i], dx, dy);

}

},

// 生成指定個數的隨機文字

randomText: function(len) {

var source = ['a', 'b', 'c', 'd', 'e',

'f', 'g', 'h', 'i', 'j',

'k', 'l', 'm', 'o', 'p',

'q', 'r', 's', 't', 'u',

'v', 'w', 'x', 'y', 'z'];

var result = [];

var sourceLen = source.length;

for(var i=0; i< len; i++) {

var text = this.generateUniqueText(source, result, sourceLen);

result.push(text)

}

return result.join('')

},

// 生成唯一文字

generateUniqueText: function(source, hasList, limit) {

var text = source[Math.floor(Math.random()*limit)];

if(hasList.indexOf(text) > -1) {

return this.generateUniqueText(source, hasList, limit)

}else {

return text

}

}

}

new Gcode('#canvas_code', {

lineNum: 6

})

})();

相關焦點

  • 開發者值得關注的HTML5新特性Canvas
    本文將帶領初學者學習Canvas的入門知識。  走近Canvas 元素標籤  官方對Canvas元素標籤的定義為:Canvas(畫布)可以用來進行繪製圖形,繪製遊戲的圖案或者其他圖形圖案,允許使用腳本動態渲染點陣圖像。簡單來說,Canvas就是允許你在HTML5中,使用Javascript去繪製你喜歡的任何圖形了,包括文字,圖片、線、點、各種形狀等。
  • Canvas框架-FabricJS簡介
    簡介Fabric是一個強大而簡單的JS Canvas庫,我們能通過使用它實現在Canvas上創建、填充圖形、給圖形填充漸變顏色。 組合圖形(包括組合圖形、圖形文字、圖片等)等一系列功能。一個簡單的canvas demo通過fabric.Canvas獲取到canvas元素,並可以對canvas進行相應的設置,既可以通過獲取已存在的canvas元素,fabric也支持創建canvas元素,同樣也能對其進行相應操作
  • 12306 圖形驗證碼「虐哭」黃牛也繞暈乘客
    根據12306 的後臺監測,目前還有一些搶票軟體等技術手段試圖在破譯圖形驗證碼,但在問題和圖形中建立聯繫,機器不會比人腦更加迅速。對此,鐵路總公司相關負責人表示,將密切監測相關搶票、刷票軟體的活動,即時改進調整網站驗證碼,對於圖形驗證碼辨識度不高等問題,技術部門還將對驗證碼中數萬張圖片進行優化,剔除一些辨識度不高的圖片,提高圖片的清晰度,方便用戶體驗,為旅客提供更公平的購票環境。
  • 擺脫圖形驗證碼恐懼 今年8成火車票無需驗證碼
    還記得被圖形驗證碼統治的恐懼嗎?今年八成火車票無需驗證碼浙江在線2018年1月5日訊(浙江在線編輯 楊靜濤) 春運火車票於日前正式開始發售,今年春運自2月1日開始,3月12日結束。「返鄉」無疑是未來一個月的關鍵詞。
  • html5 canvas畫布繪製矩形和圓形
    html5為我們提供了非常有特色的標籤,canvas標籤為我們可以實現在網頁中畫畫提供了便利,接下來我們列舉他的常用操作。新建一個html5的文檔,建立一個canvas畫布,設置長寬,這裡需要特別注意,canvas標籤可以在標籤內設置width,height,也能通過css來設置,但是通過css來設置的標籤,當繪製圖形的時候會變形,所以我們建議直接在標籤內設置。
  • 熱推18個基於HTML5 Canvas開發的圖表庫
    一個動態圖形查看器,可通過JavaScript接收數據並即時更新到圖表中。  7. Graph.tk  Graph.tk是一個開源的圖形工具,可以以不同的風格呈現函數曲線。  8. Ticker Plot
  • JS+Canvas 帶你體驗「偶消奇不消」的智商挑戰
    本文原載於 SegmentFault 專欄 一個會小程序開發的iOSer 作者:huangjianke整理編輯:SegmentFault啟邏輯之高妙,因想像而自由層疊拼圖Plus 是一款需要空間想像力和邏輯推理能力完美結合的微信小遊戲。
  • 360瀏覽器開放12306驗證碼大數據實現全自動識別
    12月3日,360安全瀏覽器和360手機瀏覽器聯合宣布,通過對12306圖形驗證碼資料庫樣本和排列組合的深度分析,並藉助業內領先的好搜圖搜技術,新一代360搶票王插件從PC端到手機端,全面實現對12306圖形驗證碼的自動識別,幫用戶一鍵完成監控、刷票、自動提交、成功搶票等環節。
  • 2018春運購票攻略 12306火車票官網訂票取消圖形驗證碼
    今年,鐵路部門取消了非熱門線路的圖形驗證碼,直接提高了旅客的購票速度。同時,推出四項購票新服務,方便旅客購票。  從14開始到17日,瀋陽市民可以通過網絡、電話平臺、手機軟體購買臘月二十七到除夕的火車票了。鐵路售票也迎來了最為緊張的階段。今年有一個好消息,乘客再購買非熱門路線車票時,將不會出現圖形驗證碼。以前,12306網站網購火車票圖形碼達到581種,一次性輸入正確的僅為8%。
  • 【工具推薦】Zrender——輕量級Canvas類庫,讓繪圖大不同!
    Zrender(Zlevel Render)是一個全新的輕量級Canvas類庫,MVC封裝,數據驅動,易於擴展,可提供類DOM的分層機制和事件模型,Promise式的動畫接口,讓Canvas繪圖大不同!該項目由EFE團隊開發而來,項目託管在GitHub上。
  • 能跑源碼,還提供數據集:這裡有一個入門企業級驗證碼識別項目
    原創 機器之心 機器之心機器之心專欄作者:kerlomz網上關於驗證碼識別的開源項目眾多,但大多是學術型文章或者僅僅是一個測試 demo,那麼企業級的驗證碼識別究竟是怎樣的呢?
  • 如何用 JavaScript+Canvas 開發一款超級燒腦小遊戲?
    層疊拼圖Plus微信小遊戲採用JavaScript+Canvas實現,沒有使用任何遊戲引擎,對於初學者來說,也比較容易入門。下面是小遊戲頁面:如何解決Canvas繪圖模糊?Canvas 繪圖時,會從兩個物理像素的中間位置開始繪製並向兩邊擴散 0.5 個物理像素。
  • 12306的驗證碼為何越來越複雜?谷歌推出「驗證碼殺手」
    在年底的網絡購票高峰中,中國鐵路客戶服務中心的12306圖形驗證碼系統讓很多購票者「吐槽」。人們不禁要問,那麼複雜的驗證碼系統,到底有什麼用? 其實,驗證碼存在的最大意義,就是區分在頁面上進行輸入操作的是人還是自動化的軟體。
  • html2canvas - 動態生成海報的優質js庫
    如何把網頁上的內容用javascript來實現截圖?今天分享的html2canvas就可以。介紹在微信項目中經常會遇到動態生成海報的需求,Web前端合成圖片往往會使用canvas。canvas雖然強大,但用來合成海報非常繁瑣,一不小心就幾百行代碼了。
  • 圖形開發中的各種名詞是什麼意思?
    各平臺下 TK 實現都是統一的,因此 TK 程序可以無需修改移植各個平臺。二 可修改可以在初始化選項或運行時的命令修改幾乎所有特性。在tkinter裡,有一些固定的圖形定義,這些詞與固定的圖形綁定在一起,下面我們就來看一看這些詞。button 按鈕 按鈕是我們在GUI中,經常使用的一個部件,類似於現實世界的按鈕。進行確認或者退出操作。
  • Django實戰:與Chart.js聯用做出精美的圖表
    對於urls.py一個簡單的路由:urls.pyfrom django.urls import pathfrom mysite.core import viewsurlpatterns = [ path('pie-chart/', views.pie_chart, name='pie-chart
  • 黃牛竟如此破解12306驗證碼:真奇葩
    「今年在登錄和下訂單時都需要輸入這種圖形驗證碼,而打碼軟體的作用就是將這兩個步驟中所要輸入圖形驗證碼自動跳過。」嘗試購買2月8日目的地為長沙和武漢的車票,開始刷票後不到半分鐘,軟體就提示下訂單成功,隨後就跳出一個紅色的界面上面提示著訂單號、車次、座位等信息,並且還有一個「進入官網」的提示。隨後登陸自己的12306帳號,在官網內果然看到一個一模一樣的訂單。
  • 網友吐槽12306 正確理解複雜驗證碼背後的良苦用心
    張桂蘭  近日,一則關於「12306鐵路售票網圖形驗證碼遭到網友吐槽」消息在網絡熱傳。有網友稱,在春運搶票的關鍵時刻,自己卻被「雷人」的圖形驗證碼問題拖了後腿。鐵路部門表示,網站推出這些複雜驗證碼主要是為了打擊「黃牛」。(北京晨報12月9日)  從2015年鐵路實行「12306」網站購票以來,驗證碼也進行了不斷的更新換代,最初的驗證碼只是簡單的數字,或者數字加字母組成的簡單字符,但這種驗證碼被迅速破解。隨後「12306」開始推出加減乘除計算、閃爍變形字母等驗證碼,結果也被360、搜狗瀏覽器等攻破,導致公平的購票環境被嚴重攪亂。
  • 利用朗深雲語音中間件實現語音驗證碼的變革
    語音驗證碼已經變成了驗證碼領域的一種新興應用,驗證碼從最初的數字、圖像、郵箱驗證,發展到現在的手機號碼驗證,手機號碼對APP提供商來說,註冊用戶真實,未來價值高。目前最流行的驗證碼模式就是簡訊,很多APP或者網站都採取了簡訊動態密碼,簡訊驗證碼在普及的同時,其問題也在慢慢暴露,一是簡訊接收成功率問題,因為簡訊本身不是保證性業務;二是受垃圾簡訊的影響,驗證碼簡訊也躺著中招,嚴重影響簡訊驗證碼的下發成功率,基於這些問題,語音驗證碼開始復興。
  • 12306的驗證碼,已經擊敗了全國99%的購票者……
    然而,當你滿心歡喜地在12306網站輸入用戶名和密碼後,才發現驗證碼成了搶票之路上的第一頭「攔路虎」。話不多說,上圖↓↓↓一開始,還比較簡單難度在增加  一個關鍵詞,加上幾個像素奇低的縮略圖,你覺得這就是極限?隨著2016年春運高峰搶票大戰臨近,12306的驗證碼又煥然升級了!