Canvas 繪製 3d 圓柱體
眾所周知 Cax 是基於 2d Canvas 的跨平臺(小遊戲、小程式和Web)渲染引擎。但是能夠繪製 3d 圖表嗎? 答案是可以!有兩種方式:
- 自己計算透視投影最終各個點的座標,然後連線填充起來
- 自己按照眼睛成像經驗直接繪製 3d 的 2d 影象
本文將使用第二種方式。
快速開始
const cy = new Cylinder(60, 200, 0.5, 'red')
stage.add(cy)
stage.update()
複製程式碼
因為 Cylinder 也是繼承自 cax.Group 的自定義 element,所以可以直接新增到stage渲染展示。顯示效果如下:
會發現使用的時候只需要傳一個顏色遍可以,怎麼做到的?圓柱體裡包含了三種顏色是怎麼來的?且看原理。
實現原理
一圖勝千言,就這麼簡單!
- 左邊第一張是半透的灰色
- 第二張是紅色
- 第三張頂部橢圓是灰色,中間橢圓是半透的灰色橢圓蓋住紅色橢圓,底部是紅色橢圓
- 第四張是最終合成的影象!
且看部分實現程式碼:
const btRect = new Graphics()
btRect.beginPath().fillStyle(color).fillRect(0, 0, width, height - th)
btRect.y = th
const topEllipse = new Ellipse(width, width / 2.5, {
fillStyle: bottleColor
})
topEllipse.y = shortSize * -1
const middleEllipse = new Ellipse(width, width / 2.5, {
fillStyle: color
})
middleEllipse.y = th - shortSize
const middleEllipseMask = new Ellipse(width, width / 2.5, {
fillStyle: bottleColor
})
middleEllipseMask.alpha = 0.618
middleEllipseMask.y = th - shortSize
const bottomEllipse = new Ellipse(width, width / 2.5, {
fillStyle: color
})
bottomEllipse.y = height - shortSize
this.add(topRect, topEllipse, btRect, bottomEllipse, middleEllipse, middleEllipseMask)
複製程式碼
cax 內建的物件可以通過調整 alpha 來設定透明度,非常靈活方便,完整程式碼請到這裡檢視 → Cylinder Source
那麼問題來了?橢圓怎麼擬合?
橢圓
CanvasRenderingContext2D.ellipse() 是 Canvas 2D API 新增橢圓路徑的方法。橢圓的圓心在(x,y)位置,半徑分別是radiusX 和 radiusY ,按照anticlockwise(預設順時針)指定的方向,從 startAngle 開始繪製,到 endAngle 結束。
但是!這是一個實驗中的功能,不能在相容所有瀏覽器。
且看 → cax 怎麼實現的!
import Shape from './shape'
class Ellipse extends Shape {
constructor (width, height, option) {
super()
this.option = option || {}
this.width = width
this.height = height
}
draw () {
const w = this.width
const h = this.height
const k = 0.5522848
const ox = (w / 2) * k
const oy = (h / 2) * k
const xe = w
const ye = h
const xm = w / 2
const ym = h / 2
this.beginPath()
this.moveTo(0, ym)
this.bezierCurveTo(0, ym - oy, xm - ox, 0, xm, 0)
this.bezierCurveTo(xm + ox, 0, xe, ym - oy, xe, ym)
this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye)
this.bezierCurveTo(xm - ox, ye, 0, ym + oy, 0, ym)
if (this.option.strokeStyle) {
if (this.option.lineWidth !== undefined) {
this.lineWidth(this.option.lineWidth)
}
this.strokeStyle(this.option.strokeStyle)
this.stroke()
}
if (this.option.fillStyle) {
this.fillStyle(this.option.fillStyle)
this.fill()
}
}
}
export default Ellipse
複製程式碼
通過 4 條貝賽爾曲線去擬合一個橢圓。
更多圖表教程請關注 Wechart by Cax ,我們將持續更新!