HTML5 Canvas制作雷达图实战
雷达图又叫蜘蛛网图,是一种对各项数据查看很明显的表现图,在很多游戏中,对游戏中的每个角色的分析图一般也用这种图。
下面,用HTML5的Cavas来实现雷达图。
效果
一、创建Canvas
var mW = 400;
var mH = 400;
var mCtx = null;
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.height = mH;
canvas.width = mW;
mCtx = canvas.getContext('2d');
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
二、制作多边形背景
var mCount = 6; //边数
var mCenter = mW /2; //中心点
var mRadius = mCenter - 50; //半径(减去的值用于给绘制的文本留空间)
var mAngle = Math.PI * 2 / mCount; //角度
var mColorPolygon = '#B8B8B8'; //多边形颜色
// 绘制多边形边
function drawPolygon(ctx){
ctx.save();
ctx.strokeStyle = mColorPolygon;
var r = mRadius/ mCount; //单位半径
//画6个圈
for(var i = 0; i < mCount; i ++){
ctx.beginPath();
var currR = r * ( i + 1); //当前半径
//画6条边
for(var j = 0; j < mCount; j ++){
var x = mCenter + currR * Math.cos(mAngle * j);
var y = mCenter + currR * Math.sin(mAngle * j);
ctx.lineTo(x, y);
}
ctx.closePath()
ctx.stroke();
}
ctx.restore();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
效果:
三、连接顶点线
var mColorLines = '#B8B8B8'; //顶点连线颜色
//顶点连线
function drawLines(ctx){
ctx.save();
ctx.beginPath();
ctx.strokeStyle = mColorLines;
for(var i = 0; i < mCount; i ++){
var x = mCenter + mRadius * Math.cos(mAngle * i);
var y = mCenter + mRadius * Math.sin(mAngle * i);
ctx.moveTo(mCenter, mCenter);
ctx.lineTo(x, y);
}
ctx.stroke();
ctx.restore();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
效果:
四、绘制数据文本
var mData = [['速度', 77],
['力量', 72],
['防守', 46],
['射门', 50],
['传球', 80],
['耐力', 60]]; //数据
var mColorText = '#000000';
//绘制文本
function drawText(ctx){
ctx.save();
var fontSize = mCenter / 12;
ctx.font = fontSize + 'px Microsoft Yahei';
ctx.fillStyle = mColorText;
for(var i = 0; i < mCount; i ++){
var x = mCenter + mRadius * Math.cos(mAngle * i);
var y = mCenter + mRadius * Math.sin(mAngle * i);
//通过不同的位置,调整文本的显示位置
if( mAngle * i >= 0 && mAngle * i <= Math.PI / 2 ){
ctx.fillText(mData[i][0], x, y + fontSize);
}else if(mAngle * i > Math.PI / 2 && mAngle * i <= Math.PI){
ctx.fillText(mData[i][0], x - ctx.measureText(mData[i][0]).width, y + fontSize);
}else if(mAngle * i > Math.PI && mAngle * i <= Math.PI * 3 / 2){
ctx.fillText(mData[i][0], x - ctx.measureText(mData[i][0]).width, y);
}else{
ctx.fillText(mData[i][0], x, y);
}
}
ctx.restore();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
效果:
五、绘制数据覆盖区域
//绘制数据区域
function drawRegion(ctx){
ctx.save();
ctx.beginPath();
for(var i = 0; i < mCount; i ++){
var x = mCenter + mRadius * Math.cos(mAngle * i) * mData[i][1] / 100;
var y = mCenter + mRadius * Math.sin(mAngle * i) * mData[i][1] / 100;
ctx.lineTo(x, y);
}
ctx.closePath();
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
ctx.fill();
ctx.restore();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
效果:
六、绘制数据点
把每个数据与线的焦点绘制出来。
//画点
function drawCircle(ctx){
ctx.save();
var r = mCenter / 18;
for(var i = 0; i < mCount; i ++){
var x = mCenter + mRadius * Math.cos(mAngle * i) * mData[i][1] / 100;
var y = mCenter + mRadius * Math.sin(mAngle * i) * mData[i][1] / 100;
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';
ctx.fill();
}
ctx.restore();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
效果:
效果演示
最终代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
canvas{
}
</style>
</head>
<body>
<script type="text/javascript">
var mW = 400;
var mH = 400;
var mData = [['速度', 77],
['力量', 72],
['防守', 46],
['射门', 50],
['传球', 80],
['耐力', 60]];
var mCount = mData.length; //边数
var mCenter = mW /2; //中心点
var mRadius = mCenter - 50; //半径(减去的值用于给绘制的文本留空间)
var mAngle = Math.PI * 2 / mCount; //角度
var mCtx = null;
var mColorPolygon = '#B8B8B8'; //多边形颜色
var mColorLines = '#B8B8B8'; //顶点连线颜色
var mColorText = '#000000';
//初始化
(function(){
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.height = mH;
canvas.width = mW;
mCtx = canvas.getContext('2d');
drawPolygon(mCtx);
drawLines(mCtx);
drawText(mCtx);
drawRegion(mCtx);
drawCircle(mCtx);
})();
// 绘制多边形边
function drawPolygon(ctx){
ctx.save();
ctx.strokeStyle = mColorPolygon;
var r = mRadius/ mCount; //单位半径
//画6个圈
for(var i = 0; i < mCount; i ++){
ctx.beginPath();
var currR = r * ( i + 1); //当前半径
//画6条边
for(var j = 0; j < mCount; j ++){
var x = mCenter + currR * Math.cos(mAngle * j);
var y = mCenter + currR * Math.sin(mAngle * j);
ctx.lineTo(x, y);
}
ctx.closePath()
ctx.stroke();
}
ctx.restore();
}
//顶点连线
function drawLines(ctx){
ctx.save();
ctx.beginPath();
ctx.strokeStyle = mColorLines;
for(var i = 0; i < mCount; i ++){
var x = mCenter + mRadius * Math.cos(mAngle * i);
var y = mCenter + mRadius * Math.sin(mAngle * i);
ctx.moveTo(mCenter, mCenter);
ctx.lineTo(x, y);
}
ctx.stroke();
ctx.restore();
}
//绘制文本
function drawText(ctx){
ctx.save();
var fontSize = mCenter / 12;
ctx.font = fontSize + 'px Microsoft Yahei';
ctx.fillStyle = mColorText;
for(var i = 0; i < mCount; i ++){
var x = mCenter + mRadius * Math.cos(mAngle * i);
var y = mCenter + mRadius * Math.sin(mAngle * i);
if( mAngle * i >= 0 && mAngle * i <= Math.PI / 2 ){
ctx.fillText(mData[i][0], x, y + fontSize);
}else if(mAngle * i > Math.PI / 2 && mAngle * i <= Math.PI){
ctx.fillText(mData[i][0], x - ctx.measureText(mData[i][0]).width, y + fontSize);
}else if(mAngle * i > Math.PI && mAngle * i <= Math.PI * 3 / 2){
ctx.fillText(mData[i][0], x - ctx.measureText(mData[i][0]).width, y);
}else{
ctx.fillText(mData[i][0], x, y);
}
}
ctx.restore();
}
//绘制数据区域
function drawRegion(ctx){
ctx.save();
ctx.beginPath();
for(var i = 0; i < mCount; i ++){
var x = mCenter + mRadius * Math.cos(mAngle * i) * mData[i][1] / 100;
var y = mCenter + mRadius * Math.sin(mAngle * i) * mData[i][1] / 100;
ctx.lineTo(x, y);
}
ctx.closePath();
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
ctx.fill();
ctx.restore();
}
//画点
function drawCircle(ctx){
ctx.save();
var r = mCenter / 18;
for(var i = 0; i < mCount; i ++){
var x = mCenter + mRadius * Math.cos(mAngle * i) * mData[i][1] / 100;
var y = mCenter + mRadius * Math.sin(mAngle * i) * mData[i][1] / 100;
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';
ctx.fill();
}
ctx.restore();
}
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
代码下载:点击这里
HTML5 Canvas制作雷达图实战的更多相关文章
- 在Excel中制作雷达图
雷达图的作用 雷达图是专门用来进行多指标体系比较分析的专业图表.从雷达图中可以看出指标的实际值与参照值的偏离程度,从而为分析者提供有益的信息.雷达图一般用于成绩展示.效果对比量化.多维数据对比等等,只 ...
- 如何使用 HTML5 Canvas 制作水波纹效果
今天,我们继续分享 JavaScript 实现的效果例子,这篇文章会介绍使用 JavaScript 实现水波纹效果.水波效果以图片为背景,点击图片任意位置都会触发.有时候,我们使用普通的 Javasc ...
- python批量制作雷达图
老板要画雷达图,但是数据好多组怎么办?不能一个一个点excel去画吧,那么可以利用python进行批量制作,得到样式如下: 首先制作一个演示的excel,评分为excel随机数生成: 1 =INT(( ...
- 怎样用HTML5 Canvas制作一个简单的游戏
原文连接: How To Make A Simple HTML5 Canvas Game 自从我制作了一些HTML5游戏(例如Crypt Run)后,我收到了很多建议,要求我写一篇关于怎样利用HTML ...
- HTML5 Canvas(画布)实战编程初级篇:基本介绍和基础画布元素
欢迎大家阅读HTML5 Canvas(画布)实战编程初级篇系列,在这个系列中,我们将介绍最简单的HTML5画布编程.包括: 画布元素 绘制直线 绘制曲线 绘制路径 绘制图形 绘制颜色,渐变和图案 绘制 ...
- [译]怎样用HTML5 Canvas制作一个简单的游戏
这是我翻译自LostDecadeGames主页的一篇文章,原文地址:How To Make A Simple HTML5 Canvas Game. 下面是正文: 自从我制作了一些HTML5游戏(例如C ...
- HTML5 canvas制作童年的回忆大风车
今天看到一篇CSS3写的大风车http://www.cnblogs.com/yaojaa/archive/2013/01/30/2882521.html,感觉CSS3太神奇了,这在以前用CSS是想都不 ...
- DevExpressXtraReport—制作雷达图
存储过程: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ========================================== ...
- python+matplotlib制作雷达图3例分析和pandas读取csv操作
1.例一 图1 代码1 #第1步:导出模块 import numpy as np import matplotlib.pyplot as plt from matplotlib import font ...
随机推荐
- tomcat6和tomcat7管理用户manager配置
tomcat用户登录文件配置 如果想要对部署在tomcat上的项目进行管理查看,需要在tomcat安装目录conf文件夹下的tomcat-user.xml里添加用户登录权限.具体添加的内容如下: To ...
- Android GsmCellLocation.getCellLocation返回NULL
Android GsmCellLocation.getCellLocation返回NULL 1.首先 获取服务 telephonyManager =(TelephonyManager)getSyste ...
- cf220b
不知道为什么线段树区间更新专题里有这题.. 可以用莫队解,也可以直接开数组解 /* n个询问,m个元素 O(m*m):记录每个元素出现次数,筛掉出现次数小于数值的数 */ #include<io ...
- hdu4605
两颗线段树,分别维护向左走向右走的情况 线段树的结点维护区间有多少点被路径经过了 离线读入所有询问,dfs遍历树的每一个结点,访问到v时解决对v的所有查询,在dfs过程中只需要维护根节点到v的链,线段 ...
- python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)
昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...
- MVC开发中的常见错误-04-“System.NullReferenceException”类型的异常在 BBFJ.OA.WebApp.dll 中发生,但未在用户代码中进行处理
未将对象引用设置到对象实例,又名空指针异常,伴随程序员开发的一生. 查看详细信息得知: SetUserRoleInfo() 首先想到的是 IBLL.IRoleInfoService RoleInfo ...
- java判断给定路径或URL下的文件或文件夹是否存在?
if (file.exists()) { 来判断这是不是一个文件. file.isDirectory() 来判断这是不是一个文件夹. 1.File testFile = new File(testFi ...
- AOJ 2170 Marked Ancestor[并查集][离线]
题意: 给你一颗N个节点的树,节点编号1到N.1总是节点的根.现在有两种操作: M v: 标记节点v Q v: 求出离v最近的标记的相邻节点.根节点一开始就标记好了. 现在给一系列操作,求出所有Q操作 ...
- BZOJ 3771 Triple FFT+容斥原理
解析: 这东西其实就是指数型母函数? 所以刚开始读入的值我们都把它前面的系数置为1. 然后其实就是个多项式乘法了. 最大范围显然是读入的值中的最大值乘三,对于本题的话是12W? 用FFT优化的话,达到 ...
- 【Java】 剑指offer(25) 合并两个排序的链表
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照 ...