egret绘制环形图

之前分享过通过highcarts、echarts绘制饼图(环形图)。前段时间的H5游戏项目中,也通过egret绘制过环形图,下面就分享一下,如何通过egret绘制环形图。

效果图

先看一下效果图
egret绘制环形图

分析

这种绘制方法肯定不是只用一次,所以我们需要将这种方法封装到函数中,然后我们通过传入几个参数就可以绘制出环形图。
function drawCircle(obj, data) {}

先来分析一下这个图都有几部分组成。
首先我们可以看出环形图的颜色是分为深、浅两种颜色,中间是一个icon,下边部分是图例。

环形图主体部分

因为不是使用highcharts、echarts这种插件,所以所有的东西都需要我们自己去写,不能使用一些原有的配置。
在开始绘制之前,我们需要先算出来这个环形图要绘制成几部分,也就是传入的数据的length是多少,然后我们还需要算出绘制的起始和结束角度startDegendDeg

const length: number = data.length;
let startDeg = 0;
let endDeg = 0;
// 还有一些其他的,如要绘制的图形的宽、高等属性,根据需要自行设置即可    

在基本的配置完成后,我们需要先创建一个放置环形图及其图例的区域sprite,下面的objWidthwidth为前一步的自行设置,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循环进行外层浅色区域环形图的绘制,这里面同时也会将startDegendDeg分别赋值。

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方法使其可以在外部访问。

发表评论

邮箱地址不会被公开。 必填项已用*标注