新年伊始,学习不止。

顺带恭喜下自己博客点击量突破 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. 石墨文档Websocket百万长连接技术实践
  2. inline-block元素出现位置错位的解决方法
  3. 安装OpenResty,实现分发层、应用层nginx+lua开发(附加问题:bad argument #2 to ‘set_keepalive‘ (number expected, got nil)
  4. 【Java12】tomcatservlet(nginx,web.xml,生命周期,适配器优化),requestresponse(请求转发,登陆案例(1),重定向,文件下载)
  5. 代码设计的基础原则_设计原则:良好设计的基础
  6. 【英语学习】【WOTD】 logy 释义/词源/示例
  7. Golang 之轻松化解 defer 的温柔陷阱
  8. LVS负载均衡+三台Route Process服务器
  9. 简述导线平差计算的五个步骤_结点导线如何平差
  10. CentOS配置postgresql+postsql
  11. 微PE工具箱四合一下载并安装
  12. 基于Web的仓库管理系统的设计与实现
  13. Linux(CentOS)安装 Vim编辑器
  14. java 图片怎么设置抗锯齿,图片变形的抗锯齿处理方法
  15. 超参数调优方法整理大全
  16. 联想笔记本电脑无线网卡无法开启
  17. ipad iphone开发_如何在iPhone或iPad上删除电子邮件
  18. error:The calling thread cannot access this object because a different thread owns it解决方法
  19. p2p传输实时视频流
  20. 高斯模糊算法的实现和优化

热门文章

  1. sdn主要包含哪些接口_SDN网络架构简要介绍
  2. 如何爬取B站搜索结果
  3. 《电信增值业务经营许可证》到底有什么用?
  4. 高校计算机实验技术 面试,重实验技术型专业考研复试经验分享
  5. Python与物理 - 系统的自发性熵减及Python模拟其时间
  6. linux 系统盘做软raid,Linux软RAID配置
  7. 《财富、战争与智慧:如何在金融大难临头时幸免》毕格斯_epub+mobi+azw3
  8. ubuntu 新手 切换用户
  9. AcroFields.setFieldProperty方法如何设置文字加粗
  10. 对Largest函数的测试