在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
前言雷达图(Radar Chart) 也称为网络图、星图或蜘蛛网图。 是以从同一点开始的轴上表示的三个或更多个定量变量的二维图表的形式显示多元数据的图形方法。 适用于显示三个或更多的维度的变量。 雷达图常用于📚数据统计或对比,对于查看哪些变量具有相似的值、变量之间是否有异常值都很有用。 同时在不少游戏中都有雷达图的身影,可以很直观地展示并对比一些数据。 例如王者荣耀中的对战资料中就用到了: 那么在本篇文章中,皮皮就来分享下在 Cocos Creator 中如何利用 Graphics 组件来绘制炫酷的雷达图~
预览先来看看效果吧~
两条数据 缓动数据 花里胡哨 艺术就是爆炸 逐渐偏离主题 正文Graphics 组件在我们正式开始制作雷达图之前,让我们先来大概了解一下 Cocos Creator 引擎中的 Graphics 组件。 Graphics 组件继承于 属性(Properties)下面是我们本次将会用到的属性:
函数(Functions)下面是我们本次将会用到的函数:
画网格先来看看一个标准的雷达图有啥特点: 发现了吗?雷达图的基本特点如下:
计算轴线角度先算出轴之间的夹角度数 [ this.angles = []; // 轴间夹角 const iAngle = 360 / this.axes; for (let i = 0; i < this.axes; i++) { // 计算 const angle = iAngle * i; this.angles.push(angle); } 计算刻度坐标雷达图至少拥有 3 条轴,且每条轴上都应有 1 个或以上的刻度(不包含中心点): 所以我们需使用一个二维数组来保存所有刻度的坐标,从最外层(即轴线的末端)的刻度开始记录,方便我们绘制时读取: // 创建一个二维数组 let scalesSet: cc.Vec2[][] = []; for (let i = 0; i < 轴上刻度个数; i++) { // 用来保存当前层上的刻度坐标 let scales = []; // 计算刻度在轴上的位置 const length = 轴线长度 - (轴线长度 / 轴上刻度个数 * i); for (let j = 0; j < this.angles.length; j++) { // 将角度转为弧度 const radian = (Math.PI / 180) * this.angles[j]; // 根据三角公式计算刻度相对于中心点(0, 0)的坐标 const pos = cc.v2(length * Math.cos(radian), length * Math.sin(radian)); // 推进数组 scales.push(pos); } // 推进二维数组 scalesSet.push(scales); } 绘制轴线和外网格线轴线 连接中心点 // 遍历全部最外层的刻度 for (let i = 0; i < scalesSet[0].length; i++) { // 画笔移动至中心点 this.graphics.moveTo(0, 0); // 创建线条 this.graphics.lineTo(scalesSet[0][i].x, scalesSet[0][i].y); } 外网格线 连接所有轴上最外层 // 画笔移动至第一个点 this.graphics.moveTo(scalesSet[0][0].x, scalesSet[0][0].y); for (let i = 1; i < scalesSet[0].length; i++) { // 创建线条 this.graphics.lineTo(scalesSet[0][i].x, scalesSet[0][i].y); } // 闭合当前线条(外网格线) this.graphics.close(); 填充并绘制 这里需要注意先填充颜色再绘制线条,要不然轴线和网格线就被挡住了: // 填充线条包围的空白区域 this.graphics.fill(); // 绘制已创建的线条(轴线和外网格线) this.graphics.stroke(); 于是现在我们就有了这么个玩意儿: 绘制内网格线当刻度大于 1 个时就需要绘制内网格线,从刻度坐标集的下标 1 开始绘制: // 刻度大于 1 个时才绘制内网格线 if (scalesSet.length > 1) { // 从下边 1 开始(下标 0 是外网格线) for (let i = 1; i < scalesSet.length; i++) { // 画笔移动至第一个点 this.graphics.moveTo(scalesSet[i][0].x, scalesSet[i][0].y); for (let j = 1; j < scalesSet[i].length; j++) { // 创建线条 this.graphics.lineTo(scalesSet[i][j].x, scalesSet[i][j].y); } // 闭合当前线条(内网格线) this.graphics.close(); } // 绘制已创建的线条(内网格线) this.graphics.stroke(); } 就这样我们雷达图的底子就画好啦: 画数据编写画线逻辑之前,先确定一下我们需要的数据结构:
具体的数据结构如下(导出类型方便外部使用): /** * 雷达图数据 */ export interface RadarChartData { /** 数值 */ values: number[]; /** 线的宽度 */ lineWidth?: number; /** 线的颜色 */ lineColor?: cc.Color; /** 填充的颜色 */ fillColor?: cc.Color; /** 节点的颜色 */ joinColor?: cc.Color; } 绘制数据绘制数据比较简单,我们只需要算出数据点在图表中的位置,并将数据连起来就好了。 在 /** * 绘制数据 * @param data 数据 */ public draw(data: RadarChartData | RadarChartData[]) { // 处理数据 const datas = Array.isArray(data) ? data : [data]; // 开始绘制数据 for (let i = 0; i < datas.length; i++) { // 装填染料 this.graphics.strokeColor = datas[i].lineColor || defaultOptions.lineColor; this.graphics.fillColor = datas[i].fillColor || defaultOptions.fillColor; this.graphics.lineWidth = datas[i].lineWidth || defaultOptions.lineWidth; // 计算节点坐标 let coords = []; for (let j = 0; j < this.axes; j++) { const value = datas[i].values[j] > 1 ? 1 : datas[i].values[j]; const length = value * this.axisLength; const radian = (Math.PI / 180) * this.angles[j]; const pos = cc.v2(length * Math.cos(radian), length * Math.sin(radian)) coords.push(pos); } // 创建线条 this.graphics.moveTo(coords[0].x, coords[0].y); for (let j = 1; j < coords.length; j++) { this.graphics.lineTo(coords[j].x, coords[j].y); } this.graphics.close(); // 闭合线条 // 填充包围区域 this.graphics.fill(); // 绘制线条 this.graphics.stroke(); // 绘制数据节点 for (let j = 0; j < coords.length; j++) { // 大圆 this.graphics.strokeColor = datas[i].lineColor || defaultOptions.lineColor; this.graphics.circle(coords[j].x, coords[j].y, 2); this.graphics.stroke(); // 小圆 this.graphics.strokeColor = datas[i].joinColor || defaultOptions.joinColor; this.graphics.circle(coords[j].x, coords[j].y, .65); this.graphics.stroke(); } } } 到这里我们已经成功制作了一个可用的雷达图: 但是!我们的征途是星辰大海!必须加点料! 完全静态的雷达图实在是太无趣太普通,得想想办法让它动起来! 我们的雷达图数据的数值是数组形式,想到怎么样才能让这些数值动起来了吗? 得益于 Cocos Creator 为我们提供的 Tween 缓动系统,让复杂的数据动起来变得异常简单! 我们只需要这样,这样,然后那样,是不是很简单?
我的思路是:
每帧更新// 当前雷达图数据 private curDatas: RadarChartData[] = []; protected update() { if (!this.keepUpdating) return; // 绘制当前数据 this.draw(this.curDatas); } 缓动数据/** * 缓动绘制 * @param data 目标数据 * @param duration 动画时长 */ public to(data: RadarChartData | RadarChartData[], duration: number) { // 处理重复调用 this.unscheduleAllCallbacks(); // 包装单条数据 const datas = Array.isArray(data) ? data : [data]; // 打开每帧更新 this.keepUpdating = true; // 动起来! for (let i = 0; i < datas.length; i++) { // 数值动起来! // 遍历数据中的全部数值,逐个让他们动起来! for (let j = 0; j < this.curDatas[i].values.length; j++) { // 限制最大值为 1(即 100%) const value = datas[i].values[j] > 1 ? 1 : datas[i].values[j]; cc.tween(this.curDatas[i].values) .to(duration, { [j]: value }) .start(); } // 样式动起来! // 没有指定则使用原来的样式! cc.tween(this.curDatas[i]) .to(duration, { lineWidth: datas[i].lineWidth || this.curDatas[i].lineWidth, lineColor: datas[i].lineColor || this.curDatas[i].lineColor, fillColor: datas[i].fillColor || this.curDatas[i].fillColor, joinColor: datas[i].joinColor || this.curDatas[i].joinColor }) .start(); } this.scheduleOnce(() => { // 关闭每帧更新 this.keepUpdating = false; }, duration); } 数值和样式都动起来了:
以上就是如何在CocosCreator里画个炫酷的雷达图的详细内容,更多关于CocosCreator画个雷达图的资料请关注极客世界其它相关文章! |
请发表评论