您好,登錄后才能下訂單哦!
這篇文章主要介紹小程序怎么用canvas繪制海報,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
在canvas上繪制圖片/文字的時候,我們設定canvas:375*667的寬高,會發現繪制出來的圖片很模糊,感覺像是一張分辨率很差的圖片,文字看起來也會有疊影。
注意:物理像素是指手機屏幕上顯示的最小單元,而設備獨立像素(邏輯像素)計算機設備中的一個點,css 中設置的像素指的就是該像素。
原因:在前端開發中我們知道一個屬性叫devicePixelRatio(設備像素比)
,該屬性決定了在渲染界面時會用幾個(通常是2個)物理像素來渲染一個設備獨立像素。
舉個例,一張100*100像素大小的圖片,在retina屏幕下,會用2個像素點去渲染圖片的一個像素點,相當于圖片放大了一倍,因此圖片會變得模糊,這也是1px在retina 屏上變粗的原因。
解決: 將canvas-width和canvas-height都放大2倍,在通過style將canvas的顯示width,height縮小2 倍.
例如:
<canvas width="320" height="180" style="width:160px;height:90px;"></canvas>
rpx是小程序里特有的尺寸單位,可以根據屏幕的寬度進行自適應,而在iphone6/iphonex上,1rpx等于不同的px。所以很可能會導致在不同手機下,你的canvas展示不一致。
在繪制海報的之前,我們拿到的設計稿一般都是基于iphone6的2倍圖。而且從上一個問題的解決,我們知道canvas的大小也是2倍的,所以我們可以直接量取2倍圖的設計稿直接繪制canvas,而尺寸需要注意一下rpxtoPx.
/** * * @param {*} rpx * @param {*} int //是否變成整數 factor => 0.5 //iphone6 pixelRatio => 2 像素比 */ toPx(rpx, int) { if (int) { return parseInt(rpx * this.factor * this.pixelRatio) } return rpx * this.factor * this.pixelRatio }
在小程序中提供this.ctx.measureText(text).width
去計算文本的長度,但是如果你全數字
的話,你會發現該API永遠都計算成0.所以,最后采用模擬measureText方法去計算文本長度。
measureText(text, fontSize = 10) { text = String(text) text = text.split('') let width = 0 text.forEach(function(item) { if (/[a-zA-Z]/.test(item)) { width += 7 } else if (/[0-9]/.test(item)) { width += 5.5 } else if (/\./.test(item)) { width += 2.7 } else if (/-/.test(item)) { width += 3.25 } else if (/[\u4e00-\u9fa5]/.test(item)) { // 中文匹配 width += 10 } else if (/\(|\)/.test(item)) { width += 3.73 } else if (/\s/.test(item)) { width += 2.5 } else if (/%/.test(item)) { width += 8 } else { width += 10 } }) return width * fontSize / 10 }
字體的如果過長,會超出canvas畫布,造成繪制難看,這個時候我們就應該讓超出的部分變成...
你可以設置一個width并且循環計算計算出文本的寬度,如果超出則利用substring截取后補充...
即可。
let fillText='' let width = 350 for (let i = 0; i <= text.length - 1; i++) { // 將文字轉為數組,一行文字一個元素 fillText = fillText + text[i] // 判斷截斷的位置 if (this.measureText(fillText, this.toPx(fontSize, true)) >= width) { if (line === lineNum) { if (i !== text.length - 1) { fillText = fillText.substring(0, fillText.length - 1) + '...' } } if (line <= lineNum) { textArr.push(fillText) } fillText = '' line++ } else { if (line <= lineNum) { if (i === text.length - 1) { textArr.push(fillText) } } } }
文字劇中展示計算公式:
居中在canvas中可以用(canvas的寬度-文字寬度)/2 + x (x為字體的x軸的推移)
let w = this.measureText(text, this.toPx(fontSize, true)) this.ctx.fillText(text, this.toPx((this.canvas.width - w) / 2 + x), this.toPx(y + (lineHeight || fontSize) * index))
關于在小程序里使用網絡圖片,比如cdn上的圖片,是需要down到微信本地進行 LRU 管理,讓后續繪制同樣圖片時,節省下載時間。所以首先需要你在微信小程序的后臺配置downloadFile合法域名,其次你可以在canvas繪制之前,最好提前去down圖片,等待圖片下載好了,再開始繪制,以避免一些繪制失敗的問題。
先把 base64 轉成 Uint8ClampedArray
格式。然后再通過 wx.canvasPutImageData(OBJECT, this)
繪制到畫布上,然后把畫布導出為圖片。
使用 Canvas 繪圖成功后,直接調用該方法生成圖片,在IDE上沒有問題,但在真機上會出現生成的圖片不完整的情況,可以使用一個setTimeout來解決這個問題。
this.ctx.draw(false, () => { setTimeout(() => { Taro.canvasToTempFilePath({ canvasId: 'canvasid', success: async(res) => { this.props.onSavePoster(res.tempFilePath)//回調事件 // 清空畫布 this.ctx.clearRect(0, 0, canvas_width, canvas_height) }, fail: (err) => { console.log(err) } }, this.$scope) }, time) })
fontsize 不能使用小數 如果設置 font 中字體大小部分包含小數,則會導致整個 font 設置無效。
這個問題出現在安卓手機上,ios表現正常。一開始看到這個問題,摸不著頭腦,為什么有的正常居中有的卻往前了很多。后面發現是安卓下this.ctx.setTextAlign(textAlign)
默認是為center
,所以導致了錯亂,改成left后就正常了。
利用canvas繪制一個簡單的折線圖,只需要利用lineTo
和moveTo
倆個API
將點連接即可。利用createLinearGradient
繪制陰影。
現在的海報生成只需要按照設計稿去量取尺寸就可以,但是量取的過程還是很繁瑣的,在設計稿量不到的地方還需要手動微調一下。
后續還可以做一個web
端使用拖拽的方式去完成設計稿的事情,自動生成json
應用到小程序的海報上。
海報一開始是后端同學生成的,優點是不需要前端繪制時間,也不需要去踩微信API的坑,接口返回拿到url即可展示,但是在后端生成出來的效果不佳,畢竟這種工作更加前端一些。
前端生成海報的時候我發現耗時更長,包括圖片的下載本地而且還需要給安卓一個特意寫一個setTimeout去確保繪制正常。各種兼容性問題、手機的dpr、安卓和ios等不間斷彩蛋踩到你頭禿~ 哈哈哈哈~
在canvas開發的過程中,小程序里一直有一束微光提醒我。
我也試了試最新的canvas2d的api,的確同步了web端,寫法也更流暢,在開發者工具中看是一切正常,跑在手機上則,只顯示寬度的一半在各種機型下測試也是一樣。
以上是“小程序怎么用canvas繪制海報”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。