canvas图表详解系列(5):雷达(面积)图
雷达(面积)图
本章建议学习时间4小时
学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记)
学习目标:此教程将教会大家如何使用canvas绘制各种图表,本次讲解雷达(面积)图。
源文件下载地址:https://github.com/sutianbinde/charts
雷达(面积)图
雷达(面积)图,我们的案例展示效果如下

功能:图表可以根据数据自动变换比例,绘制中间范围的时候有由小到大的动画,鼠标移入到对应值会实现颜色变化,并且显示当前项的详细信息。
实现代码相对来说比前面讲的几个图表要简单些些,具体代码如下,相应的说明在代码注释中
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style type="text/css">
canvas{border: 1px solid #A4E2F9;}
</style>
</head>
<body>
<div id="chart" height="400" width="600" style="margin:30px;"></div> <script type="text/javascript">
function goChart(cBox,dataArr,textArr,ifFill){
// 声明所需变量
var canvas,ctx;
// 图表属性
var cWidth, cHeight, cMargin, cSpace;
var originX, originY;
// 主图属性
var tobalDots, maxValue;
var lineStartAngle,radius;
var colorArr; // 运动相关变量
var ctr, numctr, speed;
//鼠标移动
var mousePosition = {}; // 创建canvas并获得canvas上下文
canvas = document.createElement("canvas");
if(canvas && canvas.getContext){
ctx = canvas.getContext("2d");
} canvas.innerHTML = "你的浏览器不支持HTML5 canvas";
cBox.appendChild(canvas); initChart(); // 图表初始化 // 图表初始化
function initChart(){
// 图表信息
cMargin = 60;
cSpace = 60;
//将canvas扩大2倍,然后缩小,以适应高清屏幕
canvas.width = cBox.getAttribute("width")* 2 ;
canvas.height = cBox.getAttribute("height")* 2;
canvas.style.height = canvas.height/2 + "px";
canvas.style.width = canvas.width/2 + "px";
//cHeight = canvas.height - cMargin*2-cSpace*2;
//cWidth = canvas.width - cMargin*2-cSpace*2;
originX = canvas.width/2;
originY = canvas.height/2; // 柱状图信息
tobalDots = textArr.length;
var allArr = [];
for(var i=0; i<dataArr.length; i++){
allArr = allArr.concat( dataArr[i].value );
}
maxValue = Math.max.apply(null,allArr); colorArr=["#AD93DB","#3AC9CB","#5FB2ED"]; //颜色数据
// 运动相关
ctr = 1;
numctr = 40;
speed = 1; textPadding=20; //文字与文字基线线之间的间距
lineStartAngle =Math.PI+ Math.PI/tobalDots; //起始绘制角度
radius = originY-cMargin-cSpace; //半径 } drawLineLabelMarkers(); // 绘制图表轴、标签和标记
// 绘制图表轴、标签和标记
function drawLineLabelMarkers(){
ctx.font = "24px Arial";
ctx.lineWidth = 2;
ctx.strokeStyle = "#DBDBDB";
ctx.fillStyle = "#000";
var startAngle = lineStartAngle;
// 五个底图环
for(var i=0; i<6; i++){
R = radius*(1-i/5); //五个
//画一个环
ctx.beginPath();
for(var j=0; j<tobalDots+1; j++){ //多画一个闭合路径
startAngle = startAngle+2*Math.PI/tobalDots;
var x = parseInt( originX+R*Math.cos(startAngle) );
var y = originY+R*Math.sin(startAngle); ctx.lineTo(x, y);//点连线
ctx.lineTo(originX, originY);//点到圆心连线
ctx.moveTo(x, y); //绘制文字
if(i==0 && textArr[j]){
drawMarkers(textArr[j],x,y)
}
} if(i%2==0){
ctx.fillStyle = "#ECECEC";
}else{
ctx.fillStyle = "#fff";
}
ctx.closePath();
ctx.fill();
ctx.stroke();
} } // 绘制标记
function drawMarkers(text,x,y){
if(x<originX && y<=originY){
ctx.textAlign="right";
ctx.fillText(text, x-textPadding, y-textPadding);
}else if(x<originX && y>originY){
ctx.textAlign="right";
ctx.fillText(text, x-textPadding, y+textPadding);
}else if(y<=originY){
ctx.textAlign="left";
ctx.fillText(text, x+textPadding, y-textPadding);
}else{
ctx.textAlign="left";
ctx.fillText(text, x+textPadding, y+textPadding);
}
}; drawChartAnimate(); // 绘制动画
//绘制动画
function drawChartAnimate(mouseMove){
var ifTip = false;
var tipArr = null;
//循环传入的多组数据
for(var i=0; i<dataArr.length; i++){
var startAngle = lineStartAngle;
var nowArr = dataArr[i].value;
var arcArr = [];
ctx.lineWidth = 4; ctx.fillStyle = ctx.strokeStyle = colorArr[i%colorArr.length];
ctx.beginPath();
for(var j=0; j<tobalDots; j++){
var R = radius*(nowArr[j]/maxValue)*ctr/numctr;
startAngle = startAngle+2*Math.PI/tobalDots;
var x = originX+R*Math.cos(startAngle);
var y = originY+R*Math.sin(startAngle);
//console.log(x,y); ctx.lineTo(x, y);//点连线
function drawArc(x,y,color,theTipArr){
return function(){
ctx.beginPath();
ctx.fillStyle = "#fff";
ctx.strokeStyle = color;
ctx.lineWidth = 4*ctr/numctr;
ctx.arc(x,y,6*ctr/numctr,0,Math.PI*2); if(!ifTip && mouseMove && ctx.isPointInPath(mousePosition.x*2, mousePosition.y*2)){ //如果是鼠标移动的到小点上,重新绘制图表
//ctx.fillStyle = "rgba(46,199,201,1)";
//是否绘制提示
ifTip = true;
tipArr = theTipArr;
ctx.lineWidth *= 2;
} ctx.fill();
ctx.stroke();
};
}
arcArr.push( drawArc( x, y, colorArr[i%colorArr.length], [dataArr[i].name,nowArr[j],textArr[j]] ) ); //将绘制圆点方法利用闭包存起来,后面统一调用,数据多时颜色循环使用
} ctx.closePath();
if(ifFill){
ctx.globalAlpha = 0.3;
ctx.fill();
ctx.globalAlpha = 1;
}
ctx.stroke(); for(var m=0; m<arcArr.length; m++){
arcArr[m]();
} canvas.style.cursor = "default";
ifTip && drawTips(mousePosition.x*2, mousePosition.y*2,tipArr); } if(ctr<numctr){
ctr++;
setTimeout(function(){
ctx.clearRect(0,0,canvas.width, canvas.height);
drawLineLabelMarkers();
drawChartAnimate();
}, speed*=1.08);
}
} //绘制提示框
function drawTips(oX,oY,valArr){ canvas.style.cursor = "pointer";
ctx.save();
ctx.beginPath();
ctx.fillStyle = "rgba(0,0,0,0.5)";
var H = 120;
roundedRect(ctx,oX+10,oY-H/2,2*H,H,5); ctx.fillStyle = "#fff";
ctx.textAlign="left";
ctx.fillText(valArr[0]+":", oX+20,oY-H/10);
ctx.fillText(valArr[2]+":"+valArr[1], oX+20,oY+H/4);
ctx.restore();
} //绘制圆角矩形的方法
function roundedRect(ctx,x,y,width,height,radius){
ctx.moveTo(x,x+radius);
ctx.beginPath();
ctx.lineTo(x,y+height-radius);
ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
ctx.lineTo(x+width-radius, y+height);
ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
ctx.lineTo(x+width,y+radius);
ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
ctx.lineTo(x+radius,y);
ctx.quadraticCurveTo(x,y,x,y+radius);
ctx.closePath();
ctx.fill();
} //监听鼠标移动
var mouseTimer = null;
canvas.addEventListener("mousemove",function(e){
e = e || window.event;
if( e.offsetX || e.offsetX==0 ){
mousePosition.x = e.offsetX;
mousePosition.y = e.offsetY;
}else if( e.layerX || e.layerX==0 ){
mousePosition.x = e.layerX;
mousePosition.y = e.layerY;
} clearTimeout(mouseTimer);
mouseTimer = setTimeout(function(){
ctx.clearRect(0,0,canvas.width, canvas.height);
drawLineLabelMarkers();
drawChartAnimate(true); },10);
}); } var dataArr = [
{
value : [20000, 10000, 28000, 35000, 50000, 19000],
name : '预算分配'
},
{
value : [15000, 14000, 28000, 31000, 42000, 21000],
name : '实际开销'
}
]; /*
* 参数1 :需要显示canvas的dom (非canvas标签,需要指定height和width)
* 参数2:二维数据 每个数据表示需要显示的一组数据对象 (value表示数据数组,name表示此数据名称)
* 参数3:一维数组 对应上面每个数据的名字
* 参数4:中部填充是否实心 ,默认false
* */
goChart(document.getElementById("chart"),dataArr,["销售","管理","信息技术","客服","研发","市场"],true) </script>
</body>
</html>
希望大家把代码都自己敲一遍。
关注公众号,博客更新即可收到推送

canvas图表详解系列(5):雷达(面积)图的更多相关文章
- canvas图表详解系列(1):柱状图
本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...
- canvas图表详解系列(2):折线图
本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...
- canvas图表详解系列(3):动态饼状图(原生Js仿echarts饼状图)
本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...
- canvas图表详解系列(4):动态散点图
本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...
- 【转】Android Canvas绘图详解(图文)
转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文) 泡 ...
- JDBC详解系列(二)之加载驱动
---[来自我的CSDN博客](http://blog.csdn.net/weixin_37139197/article/details/78838091)--- 在JDBC详解系列(一)之流程中 ...
- JDBC详解系列(三)之建立连接(DriverManager.getConnection)
在JDBC详解系列(一)之流程中,我将数据库的连接分解成了六个步骤. JDBC流程: 第一步:加载Driver类,注册数据库驱动: 第二步:通过DriverManager,使用url,用户名和密码 ...
- Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送
Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送, ...
- Android高效率编码-第三方SDK详解系列(二)——Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能
Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 我的本意是第二篇写Mob的shareSD ...
随机推荐
- 201521145048《Java程序设计》第4周学习总结
1. 本章学习总结 学会了如何去设计一个类,尽量用private修饰属性,public修饰方法. 了解继承的目的. 了解继承和多态的关系. 了解关键字extends super final overr ...
- 201521123015 《Java程序设计》第4周学习总结
本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 1.多态:使用单一接口操作多种类型的对象. 2.private修饰属性,public修饰方法. 3 ...
- 201521123070 《JAVA程序设计》第1周学习总结
本周学习总结 1.认识了三大平台Java SE.Java EE.Java ME. 2.认识了解了JDK,JVM与JRE,且熟悉JDK的操作并下载安装. 3.学会用博客写作业了. 书面作业 Q1.为什么 ...
- [转载] sublime text 2 调试python时结果空白
之前用的时候都一切正常,今天突然就出现了这个问题.按ctrl+b执行的时候结果只有空白,查了很多文章都只提到了中文路径.系统路径等等,没有解决问题,直到看到了这篇文章:http://384444165 ...
- 201521123100《Java程序设计》 第10周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. A: 2. 书面作业 本次PTA作业题集异常.多线程 1.finally 题目4-2 1.1 截图你的提交结 ...
- 201521123101 《Java程序设计》第11周学习总结
1. 本周学习总结 2. 书面作业 本次PTA作业题集多线程 1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用synchronized修饰方法实现互斥同步访问, ...
- python读取外部文件
>>> pd.read_excel('c://111.xlsx') 年度排名 历史排名 电影名称 总票房 总人次 总场次 上映年份 操作 0 1 1 美人鱼 NaN -- -- 20 ...
- webservice第一篇【介绍、Scoket、http调用、wsimport调用】
WebService介绍 首先我们来谈一下为什么需要学习webService这样的一个技术吧-. 问题一 如果我们的网站需要提供一个天气预报这样一个需求的话,那我们该怎么做????? 天气预报这么一个 ...
- eclipse安装java ee插件方法步骤
1.本人以前使用的MyEclipse进行Javaweb开发,但是后来由于myeclipse实在太臃肿,经常在运行的过程中不流畅 (可能电脑内存也不是太高吧) !所以坚决换用eclipse,但是问题 ...
- ArcGIS连带文字注记导出为CAD格式
可以使用ArcGIS的"Export To CAD"工具将点.线.面等要素直接导出为CAD格式.如果要连带将ArcGIS中的文字标注导出为CAD格式要稍麻烦一点,下面是一个例子. ...