众所周知 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