1.前言
寫了很多的javascript和css3的文章,是時候寫一篇canvas的了。canvas是html5提供的一個新的功能!至於作用,就是一個畫布。然後畫筆就是javascript。canvas的用途非常的廣,特別是html5遊戲以及資料視覺化這兩個方面。現在canvas給我的感覺就和css3一樣,可以不用太厲害,但是必須要會基礎的用法。但是以後對canvas的需求,肯定會越來越大。所以canvas很值得學習,而且學好canvas,就是很好的一個加分項。對於這篇文章,我也是以canvas初學者的角度寫的,會有很多改善的地方。如果大家覺得我有什麼可以改善的,或者建議,歡迎指點迷津!程式碼已上傳github,需要的歡迎star(downloadImg)。
大家看這篇文章之前,要了解javascript的一些基礎,也要看著瞭解一些canvas的api(canvas-MSN教程,canvas菜鳥教程)
2.邀請卡例項
邀請卡自動生成這個會有的,畢竟有時候,很多邀請卡都是一樣的,就是被邀請的人不一樣而已,也就是說,整個邀請卡,就是一個名字不一樣,那麼下面。就寫一套程式碼,根據名字生成邀請卡!
2-1.執行效果
html程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
<html> <head> <meta charset="utf-8"> <title>下載圖片</title> <style> .set-option { float: left; width: 400px; } .set-option .text { width: 200px; height: 40px; padding-left: 10px; border-radius: 4px; border: 1px solid #ccc; } .set-option td { padding: 10px 0; } .set-option td:first-child { text-align: right; padding-right: 10px; } .set-option p { margin: 0; line-height: 16px; } .check-box { width: 16px; height: 16px; margin: 0; vertical-align: top; } button { width: 200px; height: 50px; border: none; color: #fff; font-size: 16px; cursor: pointer; display: block; margin: 10px auto; } button:hover { opacity: .9; } .btn-all { background: #f90; } .btn-save { background: #09f; } .btn-download { background: #4CAF50; } </style> </head> <body> <div> <div class="set-option"> <table> <tr> <td>畫布尺寸</td> <td><input type="text" class="text" id="size"/></td> </tr> <tr> <td>背景圖片</td> <td><input type="file" id="file"/></td> </tr> <tr> <td>使用者名稱</td> <td> <input type="text" class="text" id="user-name"/> </td> </tr> <tr> <td>使用者名稱x座標</td> <td> <input type="number" class="text" id="text-option-x"/></br> <p><input type="checkbox" class="check-box" value="1" id="is-center-x">居中顯示</p> </td> </tr> <tr> <td>使用者名稱y座標</td> <td> <input type="number" class="text" id="text-option-y"/></br> <p><input type="checkbox" class="check-box" value="1" id="is-center-y">居中顯示</p> </td> </tr> <tr> <td>使用者名稱字型大小</td> <td><input type="number" class="text" id="text-size"/></td> </tr> <tr> <td>文字顏色</td> <td><input type="text" class="text" id="text-color"/></td> </tr> <tr> <td>圖片型別</td> <td> <select type="text" class="text" id="img-type"> <option value="jpg">jpg</option> <option value="png">png</option> </select> </td> </tr> </table> <button id="save-image" class="btn-save">效果預覽</button> <button id="download-img" class="btn-download">下載當前圖片</button> <button id="download-all" class="btn-all">批量匯出</button> </div> <div class="show-canvas"> <canvas width=200 height=200 id="thecanvas"></canvas> </div> </div> </body> </html> |
效果如圖,那麼大家細想一下,關於一張邀請卡,有什麼東西是需要改變的!看到上圖相比不難發現!有如下需要改變的屬性:圖片的大小,圖片,使用者名稱,使用者名稱的座標(x,y,x軸是否居中,y軸是否居中),使用者名稱字型的大小,使用者名稱字型的顏色,以及下載圖片的型別。
這樣就得到了如下的引數(大家看到有些引數是有值的,可以想成預設值就行了)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
var option = { img: '111.jpg', width: 500, height: 350, fontSize: "20px Microsoft YaHei", color: "black", text: '守候', imgType: 'jpg', x: 30, y: 30, xCenter: false, yCenter: false, }; |
2-2.步驟
1.初步效果
根據上面的引數,先初步畫一個效果,程式碼基本都是一個寫法,沒什麼技巧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
//畫圖 function draw(obj) { var canvas = document.getElementById("thecanvas"); //畫布大小 canvas.width = obj.width; canvas.height = obj.height; //設定圖片 var img = new Image(); img.src = obj.img; var ctx = canvas.getContext("2d"); //設定字型的座標 var _x = obj.x, _y = obj.y; //是否居中顯示 if (obj.xCenter) { _x = obj.width / 2; } if (obj.yCenter) { _y = obj.height / 2; } //圖片載入後 img.onload = function () { //先畫圖片 ctx.drawImage(img, 0, 0); //設定文字的大小 ctx.font = obj.fontSize; //設定文字的顏色 ctx.fillStyle = obj.color; //設定文字座標 if (obj.xCenter) { ctx.textAlign = "center"; } //畫文字 ctx.fillText(obj.text, _x, _y); }; } window.onload = function () { draw(option); } |
2.動態改變引數
看到圖已經畫好了,工作其實已經完成一半了!
下面就是動態改變引數!這一步其實很簡單。
首先,改變畫布的尺寸
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//畫布尺寸 //獲取按鈕 var size = document.getElementById("size"); size.addEventListener("blur", function () { //根據空格,區分高寬 var _width = parseInt(size.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/)[0]), _height = parseInt(size.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/)[1]); //把引數的width和height改掉 option.width = _width || 100; option.height = _height || 100; //重新畫圖 draw(option); }); |
上面程式碼設定了,只要輸入框失去了焦點,就會改變畫布的大小,下面來執行下,看下效果(gif圖差強人意,大家看懂就好)
canvas沒有層級的說法,只要改canvas,都要重繪。哪怕就是一個字移動一個畫素。
做好了這個,下面做選擇圖片的功能!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//選擇圖片 //獲取圖片控制元件 var file = document.getElementById("file"), imagesFile, imageData; file.addEventListener('change', function (e) { //獲取圖片 imagesFile = e.target.files[0]; //把圖片轉base64 var reader = new FileReader(); reader.readAsDataURL(imagesFile); //圖片載入後 reader.onload = function (e) { //設定option的img屬性,再衝洗年繪製 imageData = this.result; option.img = imageData; draw(option); } }); <img src="https://segmentfault.com/img/bVZX7E?w=991&h=797" /> |
下面開始改文字,使用者名稱這個有點不一樣,我以空格分割。如果輸入多個使用者名稱,以第一個使用者名稱重繪。下面程式碼,註釋就不寫了,還是和上面的邏輯一樣!
1 2 3 4 5 6 7 8 9 |
//使用者名稱 var userName = document.getElementById("user-name"); userName.addEventListener("blur", function () { var _text = userName.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/); option.text = _text[0]; draw(option); }); <img src="https://segmentfault.com/img/bVZUnM?w=949&h=703" /> |
下面開始使用者名稱的座標,程式碼方面,也是改option的相關屬性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
optionXCenter.addEventListener("change", function () { if (optionXCenter.checked) { option.xCenter = true; } else { option.xCenter = false; option.x = parseInt(optionX.value); } draw(option); }); //縱座標 var optionY = document.getElementById("text-option-y"); optionY.value = option.y; var optionYCenter = document.getElementById("is-center-y"); optionY.addEventListener("input", function () { if (optionYCenter.checked) { option.yCenter = true; } else { option.yCenter = false; option.y = parseInt(optionY.value); } draw(option); }); //是否垂直居中顯示 optionYCenter.addEventListener("change", function () { if (optionYCenter.checked) { option.yCenter = true; } else { option.yCenter = false; option.y = parseInt(optionY.value); } draw(option); }); |
其他的屬性,字型大小和顏色,基本是一樣的程式碼,執行的效果圖我不放了!
1 2 3 4 5 6 7 8 9 10 11 12 |
//字型顏色 var textColor = document.getElementById("text-color"); textColor.addEventListener("blur", function () { textColor.value === "" ? option.color = "#fff" : option.color = '#' + textColor.value; draw(option); }); //字型大小 var textSize = document.getElementById("text-size"); textSize.addEventListener("input", function () { textSize.value === "" ? option.fontSize = '20px Microsoft YaHei' : option.fontSize = textSize.value + 'px Microsoft YaHei'; draw(option); }); |
3.按鈕操作
效果預覽
就是預覽當前canvas的一個效果,這個就很簡單了,就是新開一個視窗,然後把圖片寫進去而已
1 2 3 4 5 6 7 8 9 10 11 |
//預覽圖片 function saveImageInfo() { var mycanvas = document.getElementById("thecanvas"); //生成圖片 var image = mycanvas.toDataURL("image/png"); var w = window.open('about:blank', 'image from canvas'); //把圖片新進新的視窗 w.document.write("<img src="%22%20+%20image%20+%20%22" alt="from canvas" />"); } var saveButton = document.getElementById("save-image"); saveButton.addEventListener('click', saveImageInfo); |
下載當前圖片
下載圖片這個,基本也是寫法的,都是些記憶的東西
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//圖片型別 var imgType = document.getElementById("img-type"); imgType.addEventListener("change",function () { option.imgType=this.value; }); //下載圖片 function downloadImg(fileName) { //獲取canvas var myCanvas = document.getElementById("thecanvas"); //設定圖片型別 var image = myCanvas.toDataURL("image/" + option.imgType).replace("image/" + option.imgType, "image/octet-stream"); var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a'); save_link.href = image; //設定下載圖片的名稱 save_link.download = fileName + '.' + option.imgType; //下載圖片 var event = document.createEvent('MouseEvents'); event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); save_link.dispatchEvent(event); } |
批量下載圖片
這個複雜一點,但也不難,下面一步一步來!
1.首先批量匯出,那麼使用者名稱我這裡是使用空格分割,那麼現在我在option裡面,弄一個欄位textAll,所有文字的集合。all代表是否是批量下載。fn屬性代表回撥函式
1 2 3 4 5 6 7 8 9 |
//批量匯出 var downloadAll = document.getElementById("download-all"); downloadAll.addEventListener('click', function () { var _text = userName.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/); option.textAll = _text; option.all = true; option.fn = downloadImg; draw(option); }); |
2.然後修改繪製的函式draw,判斷是否是全部繪製的情況!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
function draw(obj) { var canvas = document.getElementById("thecanvas"); //畫布大小 canvas.width = obj.width; canvas.height = obj.height; //設定圖片 var img = new Image(); img.src = obj.img; var ctx = canvas.getContext("2d"); //設定字型的座標 var _x = obj.x, _y = obj.y; //是否居中顯示 if (obj.xCenter) { _x = obj.width / 2; } if (obj.yCenter) { _y = obj.height / 2; } //圖片載入後 img.onload = function () { //是否是全部列印 if(obj.all){ //遍歷textAll for(var i=0;i<obj.textAll.length;i++){ //繪製圖片 ctx.drawImage(img,0,0); //設定字型大小 ctx.font=obj.fontSize; //設定字型顏色 ctx.fillStyle=obj.color; //是否居中顯示 if(obj.xCenter){ ctx.textAlign="center"; } //繪製文字 ctx.fillText(obj.textAll[i], _x,_y); //是否回撥 if(obj.fn){ obj.fn(obj.textAll[i]); } } //最後取消全部批量下載 defult.all=false; } else{ ctx.drawImage(img,0,0); ctx.font=obj.fontSize; ctx.fillStyle=obj.color; if(obj.xCenter){ ctx.textAlign="center"; } ctx.fillText(obj.text, _x,_y); } }; } |
3.小結
關於canvas入門的第一篇文章,就寫到這裡了。寫完之後,也發現自己對canvas的也是有很多的不懂!上文的這例子,知識canvas很簡單的一個入門例項。canvas如果深入學習,能做到很多讓人驚訝的效果,這個得以後要加強學習,如果發現些值得記錄的知識,我也會寫文章。canvas是一個非常值得學習的知識,也是很有趣的一個知識。期待與大家有更多的交流和學習!