1. data 数据

//data:雷达图所依据的数据
var data      = {scoreData : [{ text : '攻击', value : '45' },{ text : '力量', value : '23' },{ text : '体质', value : '67' },{ text : '精神', value : '89' },{ text : '敏捷', value : '17' },{ text : '防御', value : '49' },{ text : '速度', value : '88' },{ text : '属性', value : '17' },{ text : '爱咋咋', value : '49' }],option : {polygonBgColor : ['#f97683', '#bf93d8', '#44909e'],//多边形背景色} //自定义样式}复制代码

2. 雷达图初始化

let init = {id            : document.querySelector('#redarCanvas'), //html文件中有盛放canvas的标签canvasW       : '560', //自定义canvas 宽度canvasH       : '560', //自定义canvas 高度animationLoop : '', //data中scoreData的最大值会有动画效果animation     : '',start         : 'true', //雷达图是否要展示defaultStyle  : {polygonBgColor : ['orange', 'red', 'skyblue'],//多边形背景色Bgshadow       : {    //雷达图阴影color      : '',shadowBlur : 0},translate      : {x : 1,y : 8/9}, //图像偏移量(相对于中心点的倍数)rayLine        : {// 辐射线样式color : '#B7AB72'},pointLine      : {// 连接分数点线条样式color : 'rgba(255,255,255,.1)'},points         : {// 分数点样式size : 1/25},tipText        : {color : 'rgb(75,66,66)', //Array || StringfontSize : '64'},alpha : 0.3,Reminder       : { //右下角标注样式bgColor    : ['#f97683','#bf93d8','#44909e'],text       : ['高','中','低'],color      : 'rgba(119,119,119,1)',width      : .04,fontSize   : 1,coordinate : {x : 1/7,y : 1.05}}}
}复制代码

3. 定义一个函数objAssign,将自定义样式替换成默认样式

function objAssign(source, target) {try {var json   = JSON.parse(JSON.stringify(source))var assign = function(source, target) {for (var key in target) {if (key in source) {if (Object.prototype.toString.call(target[key])==='[object Object]') {assign(source[key], target[key])} else {if (target[key]!==source[key]) {source[key] = target[key]}}}}}assign(json, target)console.log(json)return json} catch (e) {console.error(e)return {}}
}
var pointScore = [] //将data.scoreData 中的value值保存在一个数组里面
var pointText  = [] // text值也保存在一个数组中data.scoreData.sort(function(x, y) {return x.value-y.value
})data.scoreData.forEach(function(e) {pointText.push(e.text)pointScore.push(e.value)
})if (data.option) {var polygonStyle = objAssign(init.defaultStyle, data.option)
} else {var polygonStyle = init.defaultStyle
}if (pointScore.length==3) {polygonStyle.translate.y           = 1/2//polygonStyle.Reminder.coordinate.y = 1.6
}复制代码

4. 绘制

let myCanvas   = init.id
let    ctx        = myCanvas.getContext('2d')
/*设置画布宽高*/
myCanvas.width  =  init.canvasW
myCanvas.height = init.canvasHlet width  = myCanvas.width,height = myCanvas.height
//根据设备的DPR设置画布的宽高
if (window.devicePixelRatio) {myCanvas.style.width  = width+'px'myCanvas.style.height = height+'px'myCanvas.height       = height*window.devicePixelRatiomyCanvas.width        = width*window.devicePixelRatio
}
let polygonArr = []//存放多边形实例let Radius = myCanvas.height/2.6let numofSide = pointScore.length //n边形(n>=3)var maxScore = Math.max.apply(Math, pointScore)var end = false//闪烁
var twinkleSpeed = 1
var shadowBlur   = 0/*多边形构造函数*/
function Polygon(option, ctx) {this.option         = optionthis.pointY         = option.pointY || 0this.pointX         = option.pointX || 0this.translateX     = this.pointXthis.translateY     = this.pointYthis.lengthofSide   = option.lengthofSidethis.numofSide      = option.numofSide || 3this.animationFrame = 0this.scaleRate      = 0 // 缩放比例this.radian         = 360/this.numofSide/2*Math.PI/180this.shadow         = option.shadow || undefined//多边形外接圆的半径 cos(360/numofside/2) = L/2/r;if (this.lengthofSide) {this.r = this.lengthofSide/2/Math.sin(this.radian)} else {this.r = option.r}this.isFill        = option.isFill || falsethis.strokeStyle   = option.strokeStyle || '#fff'this.fillStyle     = option.fillStyle || '#000'this.ctx           = ctxthis.isScale       = option.isScalethis.line          = 0this.drawlineSpeed = 5this.progress      = 0polygonArr.push(this)
}Polygon.prototype.draw = function() {this.pointY = this.isScale ? 0 : this.option.pointYthis.pointX = this.isScale ? 0 : this.option.pointXthis.ctx.beginPath()this.ctx.strokeStyle = this.strokeStylethis.ctx.setLineDash([])var startX = this.pointX+this.r*Math.sin(2*Math.PI*0/this.numofSide)var startY = this.pointY+this.r*Math.cos(2*Math.PI*0/this.numofSide)this.ctx.moveTo(startX, startY)for (var i = 1; i <= this.numofSide; i++) {var X = this.pointX+this.r*Math.sin(2*Math.PI*i/this.numofSide)var Y = this.pointY+this.r*Math.cos(2*Math.PI*i/this.numofSide)this.ctx.lineTo(X, Y)}if (this.shadow) {this.ctx.shadowColor   = this.shadow.colorthis.ctx.shadowBlur    = 40this.ctx.shadowOffsetY = 30} else {this.ctx.shadowBlur    = 0this.ctx.shadowColor   = 'none'this.ctx.shadowOffsetY = 0this.ctx.shadowOffsetX = 0}if (this.isFill) {this.ctx.fillStyle = this.fillStylethis.ctx.fill()}this.ctx.closePath()this.ctx.stroke()
}
复制代码

5.

Polygon.prototype.update = function() {var t          = this.animationFrame*16/1000this.scaleRate = -1/2*Math.pow(Math.E, (-6*t/1.5))*(-2*Math.pow(Math.E, (6*t/1.5))+Math.sin(12*t/1.5)+2*Math.cos(12*t/1.5))this.animationFrame += 1
}Polygon.prototype.scale = function() {this.ctx.save()this.ctx.translate(this.translateX, this.translateY)this.ctx.scale(this.scaleRate, this.scaleRate)this.draw()this.ctx.restore()
}//右下角标注
Polygon.prototype.drawReminder = function(text, color, x, y, height, width, bgColor, alpha) {var fontSize = width*polygonStyle.Reminder.fontSizethis.ctx.beginPath()this.ctx.fillStyle = bgColorthis.ctx.fillRect(x, y, width, height)this.ctx.textAlign    = 'start'this.ctx.font         = fontSize+'px 微软雅黑'this.ctx.fillStyle    = 'rgba(75,66,66,'+alpha+')'this.ctx.textBaseline = 'middle'this.ctx.fillText(text, x+width*1.4, y+height/2)this.ctx.closePath()
}
//绘制辐射线
Polygon.prototype.drawLine = function(callback) {this.ctx.beginPath()for (var i = 1; i <= this.numofSide; i++) {this.ctx.lineWidth   = myCanvas.height*.002this.ctx.strokeStyle = polygonStyle.rayLine.colorthis.ctx.setLineDash([5, 10])this.ctx.moveTo(this.pointX, this.pointY)var X = this.pointX+this.r*Math.sin(2*Math.PI*i/this.numofSide)var Y = this.pointY+this.r*Math.cos(2*Math.PI*i/this.numofSide)this.ctx.lineTo(X, Y)}this.ctx.stroke()this.ctx.closePath()
}Polygon.prototype.drawPoint = function(callback) {if (this.progress >= maxScore) {this.progress===maxScorecallback && callback()} else {this.progress += .4}/*连接分数点*/this.ctx.beginPath()this.ctx.shadowBlur  = 0this.ctx.shadowColor = ''this.ctx.strokeStyle = polygonStyle.pointLine.colorthis.ctx.setLineDash([])this.ctx.lineWidth = '2'this.ctx.moveTo(this.pointX+0.92*(this.progress*pointScore[0]/maxScore/100*this.r-this.r*polygonStyle.points.size)*Math.sin(2*Math.PI*0/this.numofSide),this.pointY+0.92*(this.progress*pointScore[0]/maxScore/100*this.r-this.r*polygonStyle.points.size)*Math.cos(2*Math.PI*0/this.numofSide))for (var j = 1; j < this.numofSide; j++) {let len = this.progress*pointScore[j]/maxScore/100*this.rthis.ctx.lineTo(this.pointX+0.9*(len-this.r*polygonStyle.points.size)*Math.sin(2*Math.PI*j/this.numofSide), this.pointY+0.9*(len-this.r*polygonStyle.points.size)*Math.cos(2*Math.PI*j/this.numofSide))}this.ctx.fillStyle = 'rgba(255, 0, 0, 0.05)'this.ctx.fill()this.ctx.closePath()this.ctx.stroke()/*绘制分数点*/for (var i = 0; i < this.numofSide; i++) {if (pointScore[i]==maxScore && this.progress >= maxScore) {this.ctx.shadowBlur  = shadowBlurthis.ctx.shadowColor = 'white'if (shadowBlur >= 40) {twinkleSpeed = -.2}if (shadowBlur <= 1) {twinkleSpeed = .2}shadowBlur += twinkleSpeed}this.ctx.beginPath()this.ctx.strokeStyle = 'white'this.ctx.setLineDash([])this.ctx.lineWidth = myCanvas.height*.004var r              = this.r*polygonStyle.points.sizeif (maxScore===0) {this.ctx.arc(this.pointX, this.pointY, r, 0, 2*Math.PI, false)} else {this.ctx.arc(this.pointX+this.progress*pointScore[i]*0.94/maxScore/100*this.r*Math.sin(2*Math.PI*i/this.numofSide), this.pointY+this.progress*pointScore[i]*0.94/maxScore/100*this.r*Math.cos(2*Math.PI*i/this.numofSide), r, 0, 2*Math.PI, false)}this.ctx.fillStyle = '#FCF3DF'this.ctx.fill()this.ctx.stroke()}
}Polygon.prototype.render = function(callback) {if (this.animationFrame >= 1000/16*1.5 || this.isScale===false) {this.isScale = falsethis.draw()callback && callback()} else {this.update()this.scale()}
}Polygon.prototype.drawTip = function(text, color, x, y, fontSize, alpha) {this.ctx.beginPath()this.ctx.font      = fontSize+'px 微软雅黑'this.ctx.fillStyle = 'rgba(75,66,66,'+alpha+')'this.ctx.textAlign = 'center'this.ctx.fillText(text, x, y)this.ctx.closePath()
}var layer1 = new Polygon({pointX      : myCanvas.width/2*polygonStyle.translate.x,pointY      : myCanvas.height/2*polygonStyle.translate.y,numofSide   : numofSide,//      lengthofSide: 100,r           : myCanvas.width/3.5,strokeStyle : polygonStyle.polygonBgColor[0],fillStyle   : polygonStyle.polygonBgColor[0],isFill      : true,isScale     : true,shadow      : polygonStyle.Bgshadow
}, ctx)
var layer2 = new Polygon({pointX      : myCanvas.width/2*polygonStyle.translate.x,pointY      : myCanvas.height/2*polygonStyle.translate.y,numofSide   : numofSide,r           : myCanvas.width/3.5*2/3,fillStyle   : polygonStyle.polygonBgColor[1],strokeStyle : polygonStyle.polygonBgColor[1],isFill      : true,isScale     : true
}, ctx)
var layer3 = new Polygon({pointX      : myCanvas.width/2*polygonStyle.translate.x,pointY      : myCanvas.height/2*polygonStyle.translate.y,numofSide   : numofSide,r           : myCanvas.width/3.5*1/3,fillStyle   : polygonStyle.polygonBgColor[2],strokeStyle : polygonStyle.polygonBgColor[2],isFill      : true,isScale     : true
}, ctx)var totalFrame     = 0
var change         = 8
var alpha          = 0
var change2        = 8
var alpha2         = 0
init.animationLoop = function() {totalFrame++ctx.clearRect(0, 0, myCanvas.width, myCanvas.height)for (var i = 0, len = polygonArr.length; i < len; i++) {if (totalFrame > 1000/16*1.5*1/5*i) {polygonArr[i].render()if (i===len-1) {polygonArr[i].render(function() {polygonArr[0].drawLine()for (var i = 2; i >= 0; i--) {let bgColor = polygonStyle.Reminder.bgColor[i], text = polygonStyle.Reminder.text[i],specX                                            = 0,color                                            = polygonStyle.Reminder.color,y                                                = (polygonStyle.Reminder.coordinate.y*polygonStyle.translate.y)*myCanvas.height+myCanvas.height/8*change/8,width                                            = polygonStyle.Reminder.width*myCanvas.heightif (i===0) {specX = width*polygonStyle.Reminder.fontSize}let x = polygonStyle.Reminder.coordinate.x*myCanvas.width+(2-i)*myCanvas.width*1/4+specXpolygonArr[0].drawReminder(text, color, x, y, width, width, bgColor, alpha)if (change > 0) {change -= 8/60alpha += 1/30}}for (var i = 0, len = pointScore.length; i < len; i++) {var restR    = Radius*1/30var x        = myCanvas.width/2*polygonStyle.translate.x+(Radius)*Math.sin(2*Math.PI*i/pointScore.length) -10var y        = myCanvas.height/2*polygonStyle.translate.y+(Radius)*Math.cos(2*Math.PI*i/pointScore.length)+myCanvas.height/8*change2/8 + 25var fontSize = init.defaultStyle.tipText.fontSizeif (Array.isArray(polygonStyle.tipText.color)) {var color = polygonStyle.tipText.color[i]} else {var color = polygonStyle.tipText.color}polygonArr[0].drawTip(pointText[i], color, x, y, fontSize, alpha2)if (change2 > 0) {change2 -= 8/60alpha2 += 1/30} else {polygonArr[0].drawPoint()}}})}}}if (true) {init.animation = requestAnimationFrame(init.animationLoop)}
}
requestAnimationFrame(init.animationLoop)复制代码

github:https://github.com/dashaosunxigui/canvas-redar

转载于:https://juejin.im/post/5b188acaf265da6e5a2056c2

canvas 实现雷达图相关推荐

  1. 利用Canvas绘制雷达图

    雷达图(蜘蛛网图)是一种常见的数据分析图表,本文采用canvas来绘制雷达图,并最终封装成一个小组件.首先来看一下最终的效果图: 如何画正多边形 以正五边形雷达图为例(其他任意正多边形也一样),如下图 ...

  2. HTML5 Canvas制作雷达图实战

    雷达图又叫蜘蛛网图,是一种对各项数据查看很明显的表现图,在很多游戏中,对游戏中的每个角色的分析图一般也用这种图. 下面,用HTML5的Cavas来实现雷达图. 效果 一.创建Canvas var mW ...

  3. html5雷达图绘制,Canvas 绘制雷达图

    最近做的一个需求,场景之一是绘制一个雷达图,找了一圈,似乎 AntV 下的 F2 很适合拿来主义: 但是接着又考虑了一下,我当前所做的项目并不是可视化项目,今后大概率也不会有这种可视化图表的需求,只是 ...

  4. canvas绘制雷达图

    最近做的一个需求,场景之一是绘制一个雷达图,找了一圈,似乎 AntV 下的 F2 很适合拿来主义: 但是接着又考虑了一下,我当前所做的项目并不是可视化项目,今后大概率也不会有这种可视化图表的需求,只是 ...

  5. Canvas实现雷达图效果

    一.使用Canvas实现原理 这里最难的就是坐标系旋转后的坐标使用.其他就是利用数学公式等计算一些数据. 还有就是一步一步的调试,最终才能实现想要的效果. 如果光看已经完成的代码可能体会不到具体的逻辑 ...

  6. html雷达图代码,HTML5 Canvas制作雷达图实战

    代码实现 Document canvas{ } var mW = 400; var mH = 400; var mData = [ ['速度77', 21], ['力量72', 56], ['防守46 ...

  7. 带着canvas去流浪系列之六 绘制雷达图

    [摘要] 用canvas原生API实现百度Echarts基本图表. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvas ...

  8. 【带着canvas去流浪(6)】绘制雷达图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...

  9. echarts 雷达图_【带着canvas去流浪】绘制雷达图

    使用原生canvasAPI绘制雷达图.(截图以及数据来自于百度Echarts官方示例库[查看示例链接]). 二. 重点提示 雷达图绘制的看起来并不复杂,无非就是一些路径点的连线,其中的难点都在于一些细 ...

最新文章

  1. SpringMVC处理Date类型的成员变量方法
  2. 题目1465:最简真分数
  3. a*算法的优缺点_五种聚类算法一览与python实现
  4. mysql 查数据 default无效_导入mysql数据的时候提示Field * doesn't have a default value解决方法...
  5. 大端和小端的判断及转换
  6. mysql 多条记录选择一套_2020-11-09-Mysql(练习题第一套)
  7. 山西专科学校计算机专业排名,河南单招计算机专业专科学校排名
  8. 微课|《Python编程基础与案例集锦(中学版)》第3章例题讲解(2)
  9. monkey测试_adb monkey压力测试检测安卓手机的5大步骤,你知道吗?
  10. day6常用模块,数据库操作
  11. 基于大数据的舆情分析系统架构 - 架构篇
  12. 计算机桌面背景在哪里调整,电脑中怎么设置桌面背景
  13. 云计算笔记之admin-day-05-管理用户和组、tar备份与恢复、NTP时间同步、cron计划任务、总结和答疑
  14. (二)D3D9视频显示的流程与初始化
  15. Google Paly 上传支持64 位设备APP
  16. RPG Maker MV 密码宝箱
  17. Lync 2010升级到Lync 2013之更新CU2!
  18. 哈拉比数据库;为了家人
  19. 对话NASA传奇宇航员:太空中不止有未知与神秘,还有下午茶和电影
  20. vbox 虚拟机添加usb

热门文章

  1. python并发处理机制_Python并发处理
  2. 一个有趣的问题 : 如何设计一个线程池
  3. 利用perspective 和 transform 里面的几个参数来实现旋转照片墙
  4. Docker生产环境技术栈有哪些
  5. 在同一个类中调用另一个方法没有触发 Spring AOP 的问题
  6. Ubuntu 软件源sources.list
  7. G1垃圾收集器之RSet
  8. find grep xargs
  9. Python XML解析
  10. Java并发编程系列