一、Canvas應用的背景(個人理解)及基礎語法
基礎語法
Canvas本質是一個可以使用腳本(通常爲JavaScript)來繪製圖形的 HTML 元素,默認大小爲300像素×150像素(寬×高,像素的單位是px),通過JavaScript上下文對象動態創建圖像。比如,畫線、畫矩形、塗顏色甚至生成帶二維碼的海報。原理就是一筆一筆的畫,畫一條橫線,再畫一條橫線等等,就是不斷地創建路徑、繪製路徑,然後把這個路徑封閉起來可以塗色之類的,他的底層的封裝就是放到一個數組裏形成一個路徑的數組,將這個數組傳到js底層的一個方法,然後去繪製。
- 舉個栗子:畫一個頭像
首先,你需要把這張圖片畫canvas上面,比如說你畫你這個頭像就是正方形,就在(0,0)開始畫一個圖片。那麼你在這個圖片的中心,作爲原點,然後你畫一個圓形。然後你再利用canvas語法畫一個圓弧,在這個圓弧路徑以外設置不可見以內設置可見,這個時候就形成了一個圓形頭像。
<canvas id="canvas" width="300" height="300"></canvas>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const img = new Image()
img.onload = function() {
circleImg(ctx, img, 100, 100, 50)
}
img.src="https://avatar-static.segmentfault.com/289/811/2898115528-58c35e9b79717_big64"
function circleImg(ctx, img, x, y, r) {
ctx.save()
let d = 2 * r
let cx = x + r
let cy = y + r
ctx.arc(cx, cy, r, 0, 2 * Math.PI)
ctx.stroke();
ctx.clip()
ctx.drawImage(img, x, y, d, d)
ctx.restore()
}
// 微信小程序中的[canvas](https://developers.weixin.qq.com/miniprogram/dev/component/canvas.html)與HTML5的canvas在語法有些區別,比如API就不一樣,
// 另外小程序中的canvas因爲是原生組件的層級是最高的,所以頁面中的其他組件無論設置 z-index 爲多少,都無法覆蓋原生組件
</script>
二、常用的"生成海報"的方式
我們會經常在朋友圈看到什麼算命、性格分析、測算你的智商、情商等等這些東西,都是由用戶分享出一張圖片(海報),這個圖片就是用canvas做成的,上面畫了二維碼,二維碼是一個數組兩個或循環嵌套畫小黑點用戶識別這個二維碼之後就進入他的程序,經過程序跑出來的測試結果啊什麼的,點保存的時候,就會生成一張個性海報明白。怎麼生成這種個性化海報呢?
2.1 字符串模板
此處應有案例
主要實現:與服務端約定好數據格式–>前端做好模板–>服務端用第三方工具渲染返回到客戶端img
首先與服務端約定好數據格式,比如關鍵字是什麼、頭像URL、暱稱等等,把所有放數據格式的地方用{{{}}}嵌套,告訴後端位置;然後,將前端模擬數據摳去,比如user.tags,把這一段html的字符串模板給到服務端,最後服務端拿到數據通過html2canvas這樣的第三方工具把圖片渲染返回給客戶端展示,讓用戶可以長按這張圖片保存到手機相冊。這是比較傳統的方式早些年基本上都是通過這種方式。
有什麼弊端呢?
一是第三方工具維護不及時、不支持flex佈局、ES6等語法,二是調試不方便,三是高併發的時候會出問題,特別是生成的是高清無碼的海報的時候
2.2 canvas繪製
案例: '極客時間小助手’小程序
主要實現:前端直接通過canvas生成海報
搖晃手機抽取新年籤跳到第一個頁面,需要繪製頭像、關鍵字以及保存按鈕,黃色的保存按鈕其實就是呃一張透明的png圖片,把它畫上去。那在這個button上面兒需要固定一個寬高和它差不多大小的一個空的、透明的div,在這個div上加點擊事件,這個事件就是調第二張要保存的那個canvas。第二張這個是沒有保存按鈕的但有二維碼。帶二維碼的這張canvas放哪裏呢?一種方案是定位,給一個特別大的top或left,讓它不顯示在屏幕裏邊;另一個方案是層級,預覽的這張canvas在真正要保存canvas圖片之上,但是會有問題。手機瀏覽器版本低的話,定了層級不管用,一些安卓手機也會有問題,有時候會浮上來沒被蓋住。
當然,如果要實現保存高清圖的話,還是需要處理的,那就是放大,不過這個是笨方法。最優的方法是拆解這張圖像,確保導出的canvas是最高清的,而且對用戶來說也是最省流量的。
解析:進到首頁其實關鍵字在本地就隨機取完了,在首頁index.js中的onShow方法中就通過wx.getStorageSync緩存了要畫的元素,比如關鍵字(這裏是圖片)、關鍵字解析語(也是圖片,畢竟微信小程序的canvas不支持字體)等等。搖一搖觸發重力感應事件wx.onAccelerometerChange監聽裏面的事件,獲取用戶授權拿到頭像並跳轉到poster頁面。直接就開始畫兩張圖片,一張有二維碼的(shakepage1),一張有button的(shakepage2),這裏二維碼是’死碼’,button也是在圖片的基礎上覆蓋一個view,畫完之後調canvasToTempFilePath保導出那張帶碼的,此時帶碼的這張通過css設置visibility: hidden隱藏起來。點擊按鈕觸發saveImageToPhotosAlbum將導出的這張 圖片保存到手機相冊,這裏需要授權相應的要做一些處理,比如用戶拒絕授權之後再次點擊需要 wx.showModal再次請用戶授權。基本代碼如下:(詳細源碼))
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: this.data.screenWidth,
height: this.data.screenHeight,
destWidth: this.data.screenWidth * this.data.pixelRatio, // pixelRatio爲設備的像素比
destHeight: this.data.screenHeight * this.data.pixelRatio,
canvasId: "canvasid",
success: function(e) {
console.log(e)
this.setData({
bjtempFilePath: e.tempFilePath // 拿到要保存的圖片路徑
}, function() {});
},
fail: function(e) {
console.log(e);
}
})
onUserSaveImageRight: function () {
console.log("-click-");
var _this = this;
if (!wx.saveImageToPhotosAlbum) return wx.showModal({
title: "提示",
content: "當前微信版本過低,無法使用該功能,請升級到最新微信版本後重試。"
}), void console.log("version low");
wx.getSetting({
success: function (res) {
res.authSetting["scope.writePhotosAlbum"] ? (console.log("1-已經授權《保存圖片》權限"), _this.saveimgfn()) : wx.authorize({
scope: "scope.writePhotosAlbum",
success: function () {
console.log("用戶對相冊-授權成功"), _this.saveimgfn();
},
fail: function () {
wx.showModal({
title: "提示",
content: "請您授權保存到系統相冊",
showCancel: !1,
success: function (res) {
res.confirm && wx.openSetting({
success: function (res) {
res.authSetting["scope.writePhotosAlbum"] ? setTimeout(function () {
_this.saveimgfn();
}, 500) : wx.showModal({
title: "提示",
content: "您未授權,無法將海報保存到相冊,你可以截屏得到海報,或者再次點擊'保存海報'按鈕並授權",
showCancel: !1
});
}
});
}
});
}
});
}
});
},
saveimgfn: function () {
var filePath = this.data.bjtempFilePath;
console.log(filePath), filePath ? wx.saveImageToPhotosAlbum({
filePath: filePath,
success: function (res) {
wx.showToast({
title: "保存成功",
icon: "success",
duration: 1500
});
},
fail: function () {
wx.showToast({
title: "保存失敗",
icon: "fail",
duration: 1500
});
}
}) : this.saveImage()
三、極客時間小程序-生成各種海報的解決方案
微信小程序canvas與HTM5的canvas對比
- 微信小程序canvas中層級z-index失效,小程序中canvas擁有最高級,無法二次設置;
- 微信小程序canvas不支持字體功能,特殊字體只能用圖片代替;
- 微信小程序canvas不支持繪製在線圖片,需要下載再繪製(安全域名的鍋)
- 微信小程序canvas可以實現不同尺寸屏幕自適應
var rpx;
//獲取屏幕寬度,獲取自適應單位
wx.getSystemInfo({
success: function(res) {
rpx = res.windowWidth/750
},
})
// 在繪製方法中將參數乘以相對單位即可實現自適應
const s = wx.createCanvasContext("canvas")
s.drawImage(Url, 0, 0, 265 * rpx, 262.5 * rpx)
如何導出高清海報、如何封裝;
wx.canvasToTempFilePath({
canvasId: 'image-save',
x: 0,
y: 0,
success: res => {
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
this.setData({saving: false})
utils.success('保存成功')
setTimeout(() => {wx.navigateBack()}, 500)
},
fail: err => {
this.setData({saving: false})
wx.getSetting({
success: res => {
if(!res.authSetting || !res.authSetting['scrop.writePhotoAlbum']){
wx.openSetting()
}
}
})
}
})
}
})
有問題歡迎相互指點,技術不邊界,請多多指教!!!