新年伊始,学习不止。

顺带恭喜下自己博客点击量突破 20w~啦~~ 不容易啊~~

--------------------------------------------------------------------------

王者荣耀的英雄介绍资料里,都有个雷达图,以直观的形式可以分析这个英雄的优缺点。如下图所示:图片来自网络。

为了避嫌,免得引发口水战,我隐去了具体的英雄,只谈雷达图的绘制。

先看效果。

HTML

准备一个 canvas。

<canvas id="mycan" width="800" height="600"></canvas>

JavaScript

一些基础工作:获取canvas,获取 ctx。

let mycan = document.getElementById("mycan");
let ctx = mycan.getContext("2d");

坐标点的获取

雷达图的拐角,其实就是三角函数得出来的坐标。

用 JavaScript 写出来就是:θ 是弧度。

X = Math.cos( θ  )* R

Y = Math.sin( θ )* R

每个点的坐标,可以借用循环得出,如下所示。变量 bian,雷达图的边的个数。dotsArray 是专门用来存储坐标点的数组。

for(let i = 0 ; i <= bian-1 ; i++){let angleHD = Math.PI*2 / bian * i - Math.PI/2 ;let x = r * Math.cos( angleHD );let y = r * Math.sin( angleHD );dotsArray.push({x:x,y:y});
}

基础练习:基本的多边形

雷达图的关键就是要会绘制基本的多边形。由上面的推理,可以得知,一个基本的多边形的绘制如下所示:

let mycan = document.getElementById("mycan");
let ctx = mycan.getContext("2d");
let bian = 5 ;   // 5 边形
let r = 150 ;    // 坐标点与中心的距离
let dotsArray = [];  // 坐标点数组
for(let i = 0 ; i <= bian-1 ; i++){// 角度 - PI/2 ,是让起点坐标在 12点 位置。let angleHD = Math.PI*2 / bian * i - Math.PI/2 ;let x = r * Math.cos( angleHD );let y = r * Math.sin( angleHD );dotsArray.push({x:x,y:y});
}
console.info( dotsArray );
// 开始绘制路径
ctx.beginPath();
ctx.save();
// 位移原点到canvas中心。这样,绘制坐标的时候,就不用考虑位移情况。
ctx.translate( mycan.width/2 ,mycan.height/2);
ctx.moveTo( dotsArray[0].x, dotsArray[0].y );
for(let i=1; i<=dotsArray.length-1 ; i++){ctx.lineTo( dotsArray[i].x, dotsArray[i].y);
}
ctx.closePath();
ctx.stroke();
ctx.restore();

中级练习:面向对象的方式绘制多边形

以上代码为基础。现在改进下,用面向对象方式绘制多边形。

polygon.js
/*
* 多边形类:
* 参数:
* x,y  中心点坐标
* r  距离中心点的距离
* bian 边数,至少大于3
* dotsArray 存储各个点的坐标数组
* */
class Polygon{constructor(props) {this.x = 0 ;this.y = 0 ;this.r = 150 ;this.bian = 3 ;this.dotsArray = [];this.fillStyle = "#000";this.strokeStyle = "#f30";Object.assign(this, props);return this;}createPath(ctx){let {x,y, bian,r} = this;ctx.beginPath();ctx.save();for(let i = 0 ; i <= bian-1; i++ ){let angleHD = Math.PI*2 / bian * i - Math.PI/2 ;let dotX = r*Math.cos( angleHD );let dotY = r*Math.sin( angleHD );this.dotsArray.push({x:dotX, y:dotY});}ctx.moveTo( this.dotsArray[0].x , this.dotsArray[0].y);for(let i=1 ; i <= this.dotsArray.length-1 ; i++){ctx.lineTo( this.dotsArray[i].x , this.dotsArray[i].y);}ctx.closePath();   // 封闭路径ctx.restore();return this;}render(ctx){let {x,y,strokeStyle, fillStyle } = this ;ctx.save();ctx.translate( x , y );ctx.strokeStyle = strokeStyle;this.createPath(ctx);ctx.stroke();ctx.restore();return this ;}
}
let mycan = document.getElementById("mycan");
let ctx = mycan.getContext("2d");let  myPolygon = new Polygon({x : mycan.width/2,y : mycan.height/2,bian : 5,r : 200
});myPolygon.render(ctx);

高级练习:绘制雷达图

把上面的类改进,拓展下,完成雷达图的绘制。

/*
* 对变形类:
* 参数:
* x,y : 中心点坐标
* r : 距离中心点的距离
* datas  各个点的文字内容
*     数据 v : 0-100 的分数
*     name:  点上的数据名称
*     false(默认) 或者[{ name:"智力", v:90},{ name:"武力", v:80},{ name:"策略", v:99},{ name:"内政", v:90}]
*
* bian 边数,至少大于3
* dotsArray 存储各个点的坐标数组
* fillStyle , strokeStyle 颜色,以深色为主
* subStrokeStyle  内部线条颜色,以浅色为主。
* font  文字大小,字体
* radarXXColor   雷达信息的相关色彩
*/
class Polygon{constructor(props) {this.x = 0 ;this.y = 0 ;this.r = 150 ;this.datas = props.datas ;this.bianNum = this.datas.length || 3  ;this.dotsArray = [];this.fillStyle = "#000";this.strokeStyle = "#000";this.subStrokeStyle = "#ccc";this.font = "18px '微软雅黑'";this.radarFillColor = "rgba(255,100,100, 0.3)"this.radarStrokeColor = "rgba(255,100,100, 1)"Object.assign(this, props);return this;}/** createBgPath : 绘制雷达图的背景。* */createBgPath(ctx){let {x,y,r,bianNum,subStrokeStyle,strokeStyle} = this;let disR = r / 5 ;let angle = Math.PI*2 / bianNum ;ctx.save();// 5 个同心多边形for(let i=0 ; i<=4 ; i++ ){let dotsX , dotsY ;ctx.beginPath();ctx.strokeStyle = subStrokeStyle;for( let j=0 ; j <= bianNum-1 ; j++ ){dotsX = Math.cos( angle*j-Math.PI/2 )*disR*(i+1);dotsY = Math.sin( angle*j-Math.PI/2 )*disR*(i+1);if( j===0 ){ctx.moveTo( dotsX, dotsY );}else{ctx.lineTo( dotsX, dotsY );}// 如果是最外面的边。存储边的各个坐标。if( i === 4 ){this.dotsArray.push({x:dotsX,y:dotsY});}}// 如果是最外面的边,更改描边色。if( i===4 ){ctx.strokeStyle = strokeStyle;}ctx.closePath();ctx.stroke();}for(let i = 0 ;  i<=this.dotsArray.length-1; i++){ctx.save();ctx.strokeStyle = subStrokeStyle ;ctx.beginPath();ctx.moveTo(0,0);ctx.lineTo(this.dotsArray[i].x, this.dotsArray[i].y);ctx.stroke();ctx.restore();}ctx.restore();return this;}/** createRadarText : 绘制雷达图的文字* */createRadarText( ctx ){let {x,y, datas ,font, dotsArray } = this;ctx.save();ctx.translate(x, y);ctx.font = font ;this.createBgPath(ctx);  // 绘制雷达图背景for(let i=0 ; i <= dotsArray.length-1 ; i++){let txt = datas[i].name ;let dx = dotsArray[i].x;let dy = dotsArray[i].y;// 根据坐标,把文本的位置做适当调整。if(dx<0){ctx.textAlign = "end" ;dx = dx - 5 ;}else if(dx>0.01){ctx.textAlign = "start" ;dx = dx + 5 ;}else{ctx.textAlign = "center" ;}if( dy < 0 ){ctx.textBaseline = "bottom";dy = dy-5 ;}else if(dy>0.01){ctx.textAlign = "top" ;dy = dy + 20 ;}else{ctx.textBaseline = "middle";}// 绘制文本,坐标在最大的多边形的几个点上ctx.fillText( txt ,dx, dy );}ctx.restore();return this;}/** 绘制雷达的点* */drawRadarDots(ctx,dotsArray){let {x,y,radarStrokeColor} = this;ctx.save();ctx.translate(x, y);ctx.fillStyle = radarStrokeColor;for(let i = 0 ; i <= dotsArray.length-1 ; i++){ctx.beginPath();ctx.arc( dotsArray[i].x , dotsArray[i].y , 5, 0,Math.PI*2);ctx.fill();}ctx.restore();return this;}/** 绘制雷达图* */drawRadar(ctx){let {x,y,r, datas, bianNum, radarFillColor,radarStrokeColor} = this;let radarDots = [];    // 雷达点数组let angle = Math.PI*2 / bianNum ;// 绘制雷达文字,含背景this.createRadarText(ctx);// 绘制雷达部分ctx.save();ctx.strokeStyle = radarStrokeColor;ctx.fillStyle = radarFillColor ;ctx.translate(x,y);ctx.beginPath();for( let i = 0 ; i<=datas.length-1 ; i++){let dx = datas[i].v/100*r*Math.cos( angle*i - Math.PI/2 );let dy = datas[i].v/100*r*Math.sin( angle*i - Math.PI/2 );radarDots.push( {x:dx,y:dy} );if( i===0 ){ctx.moveTo(dx,dy);}else{ctx.lineTo(dx,dy);}}ctx.closePath();ctx.fill();ctx.stroke();ctx.restore();// 绘制雷达点this.drawRadarDots(ctx,radarDots);console.info( radarDots );}
}
let mycan = document.getElementById("mycan");
let ctx = mycan.getContext("2d");
let myData = [{ name:"战绩", v:98},{ name:"团战", v:38},{ name:"发育", v:100},{ name:"输出", v:95},{ name:"推进", v:72},{ name:"生存", v:80}
];
let myPolygon = new Polygon({datas:myData,x:mycan.width/2 ,y:mycan.height/2 ,r:200
});
myPolygon.drawRadar(ctx);

完工~

可能有不完美的地方,后面再改进~

JavaScript 练手小技巧:我用canvas画出了王者荣耀英雄属性的雷达图相关推荐

  1. JavaScript 练手小技巧:页面高亮操作提示和蒙板

    在页面上,有时候会遇到操作提示,如下图所示. 可以很直观的告诉用户,关键的操作在哪里,有什么做作用. 需要说明的是,被高亮的部分,并不是目标的真实标签,而是用的其他标签模拟的. 真实的标签被 mask ...

  2. JavaScript 练手小技巧:#RRGGBB 和 rgb(255,255,255)颜色代码相互转换

    看到有人在 CSDN 上写颜色的转换代码,突发奇想,用 JavaScript 也写一个. 一.相关知识点 (1)常用颜色代码方式,有两种 #RRGGBB 和 rgb(255,255,255) 用 #R ...

  3. JavaScript 练手小技巧:打字小游戏

    放假闲来无事,一群小屁孩想玩我的电脑. 字都不会打,还玩电脑. 用 js 写一个打字游戏,打不到 100 分,就不要玩我的电脑~~~!!! 整体界面如下所示,一切从简~ HTML 结构 <div ...

  4. JavaScript 练手小技巧:animationend 事件及其应用小案例

    animationend 事件在 CSS 动画完成后触发. CSS 动画播放时,会发生以下三个事件: animationstart - CSS 动画开始后触发 animationiteration - ...

  5. Javascript 练手小实验:秒表计时游戏

    文章目录 一.说明 二.效果展示 三.代码 3.1 HTML 3.2 CSS 3.3 Javascript 一.说明    本游戏页面设计分为左右两栏.左上为跑马灯,左下为计时器和"STAR ...

  6. JavaScript 练手小案例:超级简单又炫酷的图片手风琴效果

    手风琴效果很流行,可以任意展开收缩内容,甚是好看. 特效要求 鼠标移动到图片上,当前图片放大,其他图片收缩. HTML <div class="pics"><ul ...

  7. click 点击图片不起作用_JavaScript 练手小案例:基于SVG的图片切换效果

    最近太忙了,自动来到rjxy后,不晓得怎么回事,忙的都没时间更博了. 昨天还有个同学跟我说,你好久没更新博客了.. 甚为惭愧~~ 正好12月来了,今天开一篇. 最近上课讲到了 SVG,不晓得同学们理解 ...

  8. 王者英雄胜率用计算机怎么算,王者荣耀英雄胜率计算哪些模式 | 手游网游页游攻略大全...

    发布时间:2016-01-23 王者荣耀英雄排行榜,王者荣耀最强上分英雄推荐~还不知道用哪个英雄打排位的小伙伴们赶紧一起来看看最强的上分英雄推荐吧!!!~~ 武则天 法师中最强的就是武则天,超短的CD ...

  9. ssm练手小项目_20 个 JavaScript+Html+CSS 练手的小项目

    前言: 最近在 GitHub 上发现了一个 vanillawebprojects[1] 开源仓库,里面收集了 20 个 JavaScript+Html+CSS的练手项目,没有使用任何框架,可以让你从基 ...

最新文章

  1. PCL点云处理算法目录
  2. wmic windows
  3. Appium移动自动化配置-ios安卓
  4. dart服务器开发性能,DartVM服务器开发(第四天)--代码优化
  5. python图像质量评价_OpenCV图像质量评价的SSIM算法(图像相似度)
  6. java 魔数_Java 字节码结构解析
  7. 用python编写脚本计算linux_利用Python3实现Linux的脚本功能 !
  8. 华为全球最快 AI 训练集群 Atlas 900 诞生!
  9. POJ 3683 Priest John's Busiest Day (算竞进阶习题)
  10. bzoj 3672 购票 点分治+dp
  11. brew切换到清华源
  12. 代谢组学常见数据库列表和简介
  13. c 转时间戳php,php日期转时间戳,指定日期转换成时间戳 筋斗云网络
  14. 计算机第三课细心小编辑教案,教案-第6课小小编辑师
  15. linux卸载杀毒软件clama,centos 6 安装clamav杀毒软件查毒
  16. 草稿cfmm~yuyu 22.9.26 Linux
  17. Solana中的account
  18. 第十二周项目5-迷宫问题之图深度优先遍历解法
  19. 基于CentOS7.2安装win7虚拟机
  20. nvme分区选mbr还是guid_硬盘分区不求人:秒懂MBR和GPT分区表

热门文章

  1. [MySQL] 数据的导入
  2. c# 三维向量常用运算函数
  3. jenkins publish over ssh远程发送文件夹(目录)的一个坑(指定了文件夹路径却没有发送成功)
  4. 苹果xr一直在白苹果_苹果watcyouve一直戴错了苹果手表
  5. Nginx是什么,是干嘛的
  6. 年薪可达千万 为什么CISO这么抢手?
  7. 基于机智云物联网平台的智能种树小车
  8. 【干货】更新查看pip版本
  9. 微信分享网页链接不显示小图标怎么办
  10. python线条加粗_python docx 设置word表格边框(颜色/线型/粗细)