衆所周知 Cax 既能開發遊戲、又能開發圖表。本文將從餅圖開始 Wechart 的圖表之旅。
Wechart 徹底基於 Group 體系構建(自定義 Element) ,易維護,可擴展,任何場景可插拔使用。javascript
建立餅圖實例:css
const pie = new Pie([ { name: 'WeChat', value: 10 }, { name: 'Canvas', value: 15 }, { name: 'Cax', value: 23 }, { name: 'Tencent', value: 7 }, { name: 'Wepay', value: 22 } ], { processing: (item) => { return item.value }, x: 200, y: 200, r: 160, circleColor: 'white', textOffsetY: -12, font: '20px Arial', color: (index) => { return ['#4BC0C0', '#FF6485', '#FFA07A', '#ADACB9', '#A37AC1'][index] }, label: (item) => { return item.name }, tooltip: (item) => { return item.name + '<br/>' + item.value } } )
上面各項配置項很清晰明瞭,不作解釋,開發者可自行修改參數看餅圖的變化,下面把餅圖添加到舞臺:java
const stage = new cax.Stage(640, 400, 'body') stage.add(pie) stage.update()
stage 是最大的容器,經過 add 方法往裏面加對象,而後 update 舞臺就能顯示。git
顯示和隱藏餅圖:github
pie.show() pie.hide()
看到上面的 DEMO 能夠會有幾方面技術須要講解:canvas
先看 cax 內置的 Group 對象, Group 用於分組, group 也能夠嵌套 group,父容器的屬性會疊加在子屬性上, 好比:ide
const group = new cax.Group() const rect = new cax.Rect(100, 100 { fillStyle: 'black' }) group.add(rect) stage.add(group) stage.update()
Pie 對象正是自定義 Element,繼承自 Group:動畫
class Pie extends Group { constructor (data, option) { super()
通常狀況下,稍微複雜組合體都建議使用繼承自 Group,這樣利於擴展也方便管理自身內部的元件。
能夠看到小遊戲的 DEMO 裏的 Player、Bullet、Enemy、Background 全都是繼承自 Group。3d
Cax 內置 Graphics,可使用連綴 Canvas API 的方式繪製圖形:code
const sector = new cax.Graphics() sector .beginPath() .moveTo(0, 0) .arc(0, 0, 30, 0, Math.PI/2) .closePath() .fillStyle('green') .fill() .strokeStyle('red') .lineWidth(2) .stroke() stage.add(sector)
這裏假設你已經建立好了舞臺。效果以下:
因此一個餅圖就是把圓分紅若干個扇形。怎麼分? arc 方法傳入動態數據:
let current = 0 data.forEach((item, index) => { const sector = new cax.Graphics() sector .beginPath() .moveTo(0, 0) .arc(0, 0, 30, current, current += Math.PI * 2 * item.value / totalValue) .closePath() .fillStyle('green') .fill() .strokeStyle('red') .lineWidth(2) .stroke() })
其中 totalValue 爲全部 item.value 的和。能夠看到上面是平分一個圓。那麼怎麼平分一個扇形?能運動平分的角度嗎?
看這行代碼:
.arc(0, 0, 30, current, current += Math.PI * 2 * item.value / totalValue)
把 Math.PI * 2 改爲 totalAngle 動態變量就能夠!
let totalAngle = 0 ... ... .arc(0, 0, 30, current, current += totalAngle * item.value / totalValue)
運動 totalAngle 而且進行重繪:
cax.To.get(option) .to({ totalAngle: Math.PI * 2 }, option.duration, option.easing) .progress((object) => { current = option.begin sectorGroup.forEach((item, index) => { item .clear() .beginPath() .moveTo(0, 0) .arc(0, 0, r, current, current += object.totalAngle * option.processing(item) / totalValue) .closePath() .fillStyle(option.color(index)) .fill() .strokeStyle(option.circleColor) .lineWidth(2) .stroke() .closePath() }) }) ... ... ...
使用 cax 內置的 to2to 運動能力。這裏須要提醒的是,progress 方法會不斷地執行,爲了防止 sector 的 graphics path 不斷疊加,在循環執行的代碼裏必定要調用 clear 來清除 graphics 的之前的 Canvas 繪製命令。
文字和走線分四種狀況:
if (angle >= 0 && angle < Math.PI / 2) { } else if (angle >= Math.PI / 2 && angle < Math.PI) { } else if (angle >= Math.PI && angle < Math.PI + Math.PI / 2) { } else }
須要注意的是:
從 javascript 裏會發現 canvas 的寬高是 640*400:
const stage = new cax.Stage(640, 400, 'body')
就和咱們平時使用兩倍圖同樣,在移動端經過 media 把 canvas 變成一半寬度:
@media screen and (max-width: 500px) { canvas { width : 320px } }
這個時候會出現一個問題!由於 cax 會把 canvas 上的事件過分給 cax 內置對象,事件發生的座標由於 canvas 寬高的變化而變化了, 移動端點擊事件觸發位置不許確了!這個時候須要 scaleEventPoint 方法來校訂座標:
if (window.innerWidth <= 500) { stage.scaleEventPoint(0.5, 0.5) }
搞定!這樣無論是在 PC 鼠標仍是移動 Mobile 觸摸都能精準觸發事件。
function fadeIn(obj) { obj.alpha = 0 To.get(obj).to({ alpha: 1 }, 600).start() } function fadeOut(obj) { obj.alpha = 1 To.get(obj).to({ alpha: 0 }, 600).start() } function bounceIn(obj, from, to) { from = from || 0 obj.from = from To.get(obj).to({ scaleX: to || 1, scaleY: to || 1 }, 300, cax.easing.bounceOut).start() } function bounceOut(obj, from, to) { from = from || 1 obj.from = from To.get(obj).to({ scaleX: to || 0, scaleY: to || 0 }, 300, cax.easing.bounceOut).start() }
基於 cax 內置的 to2to 動畫引擎封裝了四個方法。
sector.hover(function (evt) { bounceIn(sector, 1, 1.1) tooltip.style.left = (evt.pureEvent.pageX + 5) + 'px' tooltip.style.top = (evt.pureEvent.pageY + 5) + 'px' tooltip.innerHTML = option.tooltip(data[index]) tooltip.style.display = 'block' }, function (evt) { bounceOut(sector, 1.1, 1) tooltip.style.display = 'none' }, function (evt) { tooltip.style.left = (evt.pureEvent.pageX + 5) + 'px' tooltip.style.top = (evt.pureEvent.pageY + 5) + 'px' })
Cax 內置對象擁有 hover(over, out, move)
方法來監聽鼠標或者手指 over、out 和 move。
Tooltip 也是徹底基於 DOM 來實現的,這樣能夠浮在 Canvas 外面,而不會限制在 Canvas 裏面。
MIT