微信小程式允許對普通元素通過 border-radius
的設定來進行圓角的繪製,但有時候在使用 canvas
繪圖的時候,也需要圓角,例如需要將頁面上某塊區域匯出為圖片下載到本地的時候,常用的解決方法就是使用 canvas
將這塊區域繪製出來,最後匯出 canvas
即可,但是 canvas
沒有直接提供圓角的繪製 api
,所以需要 曲線救國
圓角矩形與一般矩形的區別在於,前者的四個角都是圓弧,所以只需要將一般矩形的四個角切掉,換成圓弧即可,如下圖就是一個一般矩形被切掉了四個角的樣子:
很明顯,切掉了四個角的矩形,剩下其實就是四條 line
,既然如此,完全可以跳過繪製矩形然後切角這一步,因為切角的結果就是四條邊(line
),直接繪製四條邊即可。
然後在每兩條邊的缺角處繪製弧度為 0.5 * Math.PI
的圓弧,最後這四條邊與四個圓弧所封閉的圖形就是圓角矩形:
原理知道了,程式碼就很好寫了,這裡只說幾個注意點:
- 封閉圖形的
fillStyle
顏色設定為transparent
想將封閉路徑的圖形繪製下來,需要呼叫 stroke
或 fill
方法,預設 stroke
或 fill
的顏色是 black
,但是這裡有個問題,
圓弧的繪製可能會出現鋸齒或者糊邊,如果 stroke
或 fill
的顏色,與你所需要繪製的圓角矩形的邊緣色調不一致,這種糊邊的感覺會比二者色調一致的更明顯,
下圖第一個為色調一致,第二個為色調不一致的情況:
不過據我觀測,只要不是特意放大仔細看,無論是色調是否一致,其實一般人很難注意到糊邊的事情
clip
繪製好了圓角選區之後,還需要呼叫 ctx.clip
方法來裁剪選區
save
與restore
如果這個矩形選區只是 canvas
畫布的一部分,為了避免對後續的影響,最好在 beginPath
之前,將之前的動作 save
,然後畫完後再 restore
一個關於 在 canvas
上繪製圓角圖片,並下載到本地 的可執行示例程式碼已經放到 github上了,註釋也比較詳細,需要的可自取
其中關鍵程式碼如下:
/**
*
* @param {CanvasContext} ctx canvas上下文
* @param {number} x 圓角矩形選區的左上角 x座標
* @param {number} y 圓角矩形選區的左上角 y座標
* @param {number} w 圓角矩形選區的寬度
* @param {number} h 圓角矩形選區的高度
* @param {number} r 圓角的半徑
*/
function roundRect(ctx, x, y, w, h, r) {
// 開始繪製
ctx.beginPath()
// 因為邊緣描邊存在鋸齒,最好指定使用 transparent 填充
// 這裡是使用 fill 還是 stroke都可以,二選一即可
ctx.setFillStyle('transparent')
// ctx.setStrokeStyle('transparent')
// 左上角
ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)
// border-top
ctx.moveTo(x + r, y)
ctx.lineTo(x + w - r, y)
ctx.lineTo(x + w, y + r)
// 右上角
ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)
// border-right
ctx.lineTo(x + w, y + h - r)
ctx.lineTo(x + w - r, y + h)
// 右下角
ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)
// border-bottom
ctx.lineTo(x + r, y + h)
ctx.lineTo(x, y + h - r)
// 左下角
ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)
// border-left
ctx.lineTo(x, y + r)
ctx.lineTo(x + r, y)
// 這裡是使用 fill 還是 stroke都可以,二選一即可,但是需要與上面對應
ctx.fill()
// ctx.stroke()
ctx.closePath()
// 剪下
ctx.clip()
}
複製程式碼