之前分享过通过highcarts、echarts绘制饼图(环形图)。前段时间的H5游戏项目中,也通过egret绘制过环形图,下面就分享一下,如何通过egret绘制环形图。
效果图
先看一下效果图
分析
这种绘制方法肯定不是只用一次,所以我们需要将这种方法封装到函数中,然后我们通过传入几个参数就可以绘制出环形图。
function drawCircle(obj, data) {}
先来分析一下这个图都有几部分组成。
首先我们可以看出环形图的颜色是分为深、浅两种颜色,中间是一个icon,下边部分是图例。
环形图主体部分
因为不是使用highcharts、echarts这种插件,所以所有的东西都需要我们自己去写,不能使用一些原有的配置。
在开始绘制之前,我们需要先算出来这个环形图要绘制成几部分,也就是传入的数据的length
是多少,然后我们还需要算出绘制的起始和结束角度startDeg
、endDeg
。
const length: number = data.length;
let startDeg = 0;
let endDeg = 0;
// 还有一些其他的,如要绘制的图形的宽、高等属性,根据需要自行设置即可
在基本的配置完成后,我们需要先创建一个放置环形图及其图例的区域sprite
,下面的objWidth
、width
为前一步的自行设置,obj
为传入的对象,后面就不在单独说明了。如果有不懂的地方,最后也有所有代码的汇总。
let percentBg: egret.Sprite = new egret.Sprite();
percentBg.width = width;
percentBg.height = height;
percentBg.x = (objWidth - width) / 2;
percentBg.y = 95;
obj.addChild(percentBg);
环形图的区域跟上面一样,也是创建一个sprite
,然后放置到percentBg上面。
通过for循环进行外层浅色区域环形图的绘制,这里面同时也会将startDeg
与endDeg
分别赋值。
for(let i = 0; i < length; i++) {
endDeg = (data[i].industryPercent).toFixed(2) * 3.6 + startDeg;
circleBg.graphics.beginFill(GameConfig.lightColor[i]);
circleBg.graphics.moveTo(width / 2, width / 2);
circleBg.graphics.lineTo(width, width / 2);
circleBg.graphics.drawArc(width / 2, width / 2, width / 2.3, (startDeg + 2) * Math.PI / 180, endDeg * Math.PI / 180);
circleBg.graphics.lineTo(width / 2, width / 2);
circleBg.graphics.endFill();
startDeg = endDeg;
}
先通过传入数据中的配比情况,算出endDeg
结束角度,然后通过egret的绘图API绘制。
内层深色区域绘制方法同上,只需要将半径变小即可。
绘制完成后,展现在我们面前的是下面的样子
这个跟我们的需求还相差很远,这里就需要我们在以同样的圆心,绘制上一个白色的圆形来遮挡住中间的部分。
circleBg.graphics.beginFill(GameConfig.TextColors.white); //环形图中间白色部分
circleBg.graphics.moveTo(width / 2, width / 2);
circleBg.graphics.lineTo(width, width / 2);
circleBg.graphics.drawArc(width / 2, width / 2, width / 3.5, 0, 360 * Math.PI / 180);
circleBg.graphics.lineTo(width / 2, width / 2);
circleBg.graphics.endFill();
并且再以同样的圆心,绘制上一个icon。icon因为是固定的,所以建议使用图片Bitmap
,因为绘制会比直接使用图片更加消耗性能。
let centerIcon = ZpyGameUtils.createBitmapByName("card_dark_icon_png"); //中心icon
centerIcon.x = width / 2 - centerIcon.width / 2 * 0.6;
centerIcon.y = width / 2 - centerIcon.height / 2 * 0.6;
centerIcon.scaleX = 0.6;
centerIcon.scaleY = 0.6;
circleBg.addChild(centerIcon);
环形图图例
绘制完主体部分,我们再来绘制一下图例部分。这个相对于主体环形图来说,就很简单了。icon
是图例前面的小色块,label
是图例文字部分。
let labelBg: egret.Sprite = new egret.Sprite();
labelBg.width = width - 40;
labelBg.x = 20;
labelBg.y = width;
for (let i = 0, len = data.length; i < len; i++) {
let icon: egret.Shape = new egret.Shape();
icon.graphics.beginFill(GameConfig.darkColor[i]);
icon.graphics.drawRect(0, i * lineHeight, 20, 20);
icon.graphics.endFill();
labelBg.addChild(icon);
let label: egret.TextField = ZpyGameUtils.createText(data[i].industryName + ' ' + (data[i].industryPercent).toFixed(2) + '%', GameConfig.TextColors.black, 20);
label.x = 30;
label.y = lineHeight * i;
labelBg.addChild(label);
}
可滑动
因为环形图的数据可能很多,图例一页可能会显示不过来,所以我们还需要一个可以上下滑动的组件来扩展。
let percentTotalBg: egret.Sprite = new egret.Sprite();
percentTotalBg.width = width;
percentTotalBg.addChild(labelBg);
percentTotalBg.height = width + length * lineHeight;
var scrollView: egret.ScrollView = new egret.ScrollView();
scrollView.setContent(percentTotalBg);
scrollView.width = width;
scrollView.height = height;
percentBg.addChild(scrollView);
前面步骤中生成的所元素最终会放置到percentTotalBg
上,然后声明一个滑动区域scrollView
,通过setContent
方法将所有元素的区域设置为可滑动的区域。
最终代码
function drawCircle(obj, data) {
const objWidth: number = obj.width;
const objHeight: number = obj.height;
const width: number = obj.width * 0.8; //新创建的背景的宽度,宽高相同
const height: number = obj.height * 0.8; //新创建的背景的高度
const lineHeight: number = 35;
const length: number = data.length; //数据长度
let startDeg = 0; //扇形起始角度
let endDeg = 0; //结束角度
let percentBg: egret.Sprite = new egret.Sprite();
percentBg.width = width;
percentBg.height = height;
percentBg.x = (objWidth - width) / 2;
percentBg.y = 95;
obj.addChild(percentBg);
let percentTotalBg: egret.Sprite = new egret.Sprite();
percentTotalBg.width = width;
let circleBg: egret.Sprite = new egret.Sprite();
percentTotalBg.addChild(circleBg);
circleBg.width = width;
circleBg.height = width;
circleBg.y = 0;
for (let i = 0; i < length; i++) { //环形图浅色部分
endDeg = (data[i].industryPercent).toFixed(2) * 3.6 + startDeg;
circleBg.graphics.beginFill(GameConfig.lightColor[i]);
circleBg.graphics.moveTo(width / 2, width / 2);
circleBg.graphics.lineTo(width, width / 2);
circleBg.graphics.drawArc(width / 2, width / 2, width / 2.3, (startDeg + 2) * Math.PI / 180, endDeg * Math.PI / 180);
circleBg.graphics.lineTo(width / 2, width / 2);
circleBg.graphics.endFill();
startDeg = endDeg;
}
for (let i = 0; i < length; i++) { //环形图深色部分
endDeg = (data[i].industryPercent).toFixed(2) * 3.6 + startDeg;
circleBg.graphics.beginFill(GameConfig.darkColor[i]);
circleBg.graphics.moveTo(width / 2, width / 2);
circleBg.graphics.lineTo(width, width / 2);
circleBg.graphics.drawArc(width / 2, width / 2, width / 2.6, (startDeg + 2) * Math.PI / 180, endDeg * Math.PI / 180);
circleBg.graphics.lineTo(width / 2, width / 2);
circleBg.graphics.endFill();
startDeg = endDeg;
}
circleBg.graphics.beginFill(GameConfig.TextColors.white); //环形图中间白色部分
circleBg.graphics.moveTo(width / 2, width / 2);
circleBg.graphics.lineTo(width, width / 2);
circleBg.graphics.drawArc(width / 2, width / 2, width / 3.5, 0, 360 * Math.PI / 180);
circleBg.graphics.lineTo(width / 2, width / 2);
circleBg.graphics.endFill();
let centerIcon = ZpyGameUtils.createBitmapByName("card_dark_icon_png"); //中心icon
centerIcon.x = width / 2 - centerIcon.width / 2 * 0.6;
centerIcon.y = width / 2 - centerIcon.height / 2 * 0.6;
centerIcon.scaleX = 0.6;
centerIcon.scaleY = 0.6;
circleBg.addChild(centerIcon);
percentTotalBg.addChild(circleBg);
let labelBg: egret.Sprite = new egret.Sprite();
labelBg.width = width - 40;
labelBg.x = 20;
labelBg.y = width;
for (let i = 0, len = data.length; i < len; i++) {
let icon: egret.Shape = new egret.Shape();
icon.graphics.beginFill(GameConfig.darkColor[i]);
icon.graphics.drawRect(0, i * lineHeight, 20, 20);
icon.graphics.endFill();
labelBg.addChild(icon);
let label: egret.TextField = ZpyGameUtils.createText(data[i].industryName + ' ' + (data[i].industryPercent).toFixed(2) + '%', GameConfig.TextColors.black, 20);
label.x = 30;
label.y = lineHeight * i;
labelBg.addChild(label);
}
percentTotalBg.addChild(labelBg);
percentTotalBg.height = width + length * lineHeight;
var scrollView: egret.ScrollView = new egret.ScrollView();
scrollView.setContent(percentTotalBg);
scrollView.width = width;
scrollView.height = height;
percentBg.addChild(scrollView);
}
如果是在namespace中,请不要忘记通过export方法使其可以在外部访问。