Wechart 饼图
预览
众所周知 Cax 既能开发游戏、又能开发图表。本文将从饼图开始 Wechart 的图表之旅。
Wechart 完全基于 Group 体系构建(自定义 Element) ,易维护,可扩展,任何场景可插拔使用。
快速开始
创建饼图实例:
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
}
}
)
上面各项配置项很清晰明了,不做解释,开发者可自行修改参数看饼图的变化,下面把饼图添加到舞台:
const stage = new cax.Stage(640, 400, 'body')
stage.add(pie)
stage.update()
stage 是最大的容器,通过 add 方法往里面加对象,然后 update 舞台就能显示。
显示和隐藏饼图:
pie.show()
pie.hide()
实现原理
看到上面的 DEMO 可以会有几方面技术需要讲解:
- Pie 对象和 Group 的关系
- Cax 扇形绘制
- 展开和收缩动画实现
- 文字和文字走线显示在对应扇形的中间
- 显示兼容 PC 和 Mobile
- 交互兼容 PC 和 Mobile
- 渐变和点击弹出和移除收缩实现
- Tooltip 实现
Pie 对象和 Group 的关系
先看 cax 内置的 Group 对象, Group 用于分组, group 也可以嵌套 group,父容器的属性会叠加在子属性上, 比如:
- group 的 x 是 100, group 里的 bitmap 的 x 是 200, 最后 bitmap 渲染到 stage 上的 x 是 300
- group 的 alpha 是 0.7, group 里的 bitmap 的 alpha 是 0.6, 最后 bitmap 渲染到 stage 上的 alpha 是 0.42
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。
扇形绘制
Cax 内置 Graphics,可以使用连缀 Canvas API 的方式绘制图形:
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
}
需要注意的是:
- 落在左边的文字的 x 坐标需要减去文件的宽度。 Cax 内置的 Text 可以使用 getWidth() 方法获取到文字的宽度
- 走线的第一根线角度也分两种情况,1、3象限平行,2、4象限平行,走线的第二根先角度都是平行于 y 轴(如上图所示,相同颜色圈中的线是平行的)
显示与交互兼容 PC 和 Mobile
从 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 动画引擎封装了四个方法。
Tooltip 实现
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 里面。
Star && Follower
谁在使用?
License
MIT
Wechart 饼图的更多相关文章
- 读取数据库数据,并将数据整合成3D饼图在jsp中显示
首先我将生成饼图的方法独立写成一个PieChar.java类,详细代码如下:(数据库需要自己建,如有需要的话) import java.io.IOException; import java.sql. ...
- echarts饼图
1.添加点击事件并跳转到不同的页面 // 路径配置 require.config({ paths: { echarts: 'http://echarts.baidu.com/build/dist/' ...
- Html5绘制饼图统计图
这里要介绍的是一个jQuery插件:jquery.easysector.js Html5提供了强大的绘图API,让我们能够使用javascript轻松绘制各种图形.本文将主要讲解使用HTML5绘制饼图 ...
- IOS 绘制圆饼图 简单实现的代码有注释
今天为大家带来IOS 绘图中圆饼的实现 .h文件 #import <UIKit/UIKit.h> @interface ZXCircle : UIView @end .m文件 #impor ...
- Qt 之 饼图
Qt 库由许多模块组成,其中的 Qt Charts,包含了一系列图表组件. 1 饼图 (pie chart) 1.1 Charts 模块 .pro 中添加如下语句: QT += charts 头文 ...
- iOS圆饼图和圆环的绘制,并且添加引线
在开发中经常遇到统计之类的需求,特此封装了一个简单的圆饼图和圆环图,效果图如下 代码下载地址:https://github.com/minyahui/MYHCricleView.git
- ECharts饼图试玩
处理类似提交问卷的数据,要生成图表,用了ECharts,好方便的. 简陋效果: 1.表单存储 有单选和多选题,单选直接存储各选项数字值,1,2,3,4...中一个:多选用|分隔存储选项值,如1|3,2 ...
- 在Excel中制作复合饼图
在Excel中插入饼图时有时会遇到这种情况,饼图中的一些数值具有较小的百分比,将其放到同一个饼图中难以看清这些数据,这时使用复合条饼图就可以提高小百分比的可读性. 文中的复合饼图只是方便以后记忆,故不 ...
- Android AChartEngine 饼图渐变效果
二话不说,先上图 核心代码如下: private void initLabelChat(View rootView) { NumberFormat nf = new DecimalFormat(&qu ...
随机推荐
- Integert 与 int例子详解
public final class Integerextends Numberimplements Comparable<Integer> Integer 类在对象中包装了一个基本类型 ...
- [20181130]control file sequential read.txt
[20181130]control file sequential read.txt --//昨天上午探究了大量控制文件读的情况,链接:http://blog.itpub.net/267265/vie ...
- iOS 键盘上方增加工具栏
UIToolbar *keyboardDoneButtonView = [[UIToolbar alloc] init]; [keyboardDoneButtonView sizeToFit]; UI ...
- iOS application/json上传文件等
在和sever后台交互的过程中.有时候.他们需要我们iOS开发者以“application/json”形式上传. NSString *accessUrl = [NSString stringWithF ...
- 阿里云windows2012+iis8配置https
第一步先创建一个免费的证书 步骤一:申请免费证书 步骤二:填写你的二级域 步骤三:等待审核通过,通过后,点击下载 步骤四:根据自己服务器类型,下载对应的证书,根据阿里云的安装步骤做 以下是阿里云提供的 ...
- C语言入坑指南-被遗忘的初始化
前言 什么是初始化?为什么要初始化?静态变量和局部变量的初始化又有什么区别?实际应用中应该怎么做?本文将一一回答这些问题. 什么是初始化 初始化指的是对数据对象或者变量赋予初始值.例如: int va ...
- Go学习笔记04-函数
目录 函数定义 函数示例 小结 函数定义 函数定义与变量定义相似, func function_name(var1, var2, var3, ...) (return_type1, return_ty ...
- Gulp的简单使用
我比较喜欢使用Gulp,因为简单好用! 今天的任务是:使用Gulp来压缩 jQuery源码,各输出一个压缩的和未压缩的版本 第一步:安装 cnpm install gulp --save-dev cn ...
- 用js检测文本框中输入的是否符合条件并有错误和正确提醒
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- linux 软连接创建 压缩解压缩 linux的dns服务相关
linux软连接创建 注意用绝对路径,语法如下 ln -s 目标文件绝对路径 软连接名字绝对路径 ln -s /小护士.txt /tmp/hs.txt 修改linux的PS1变量,命令提示符变量 PS ...