雷达(面积)图

本章建议学习时间4小时

学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记)

学习目标:此教程将教会大家如何使用canvas绘制各种图表,本次讲解雷达(面积)图。

演示地址:https://sutianbinde.github.io/charts/%E9%9B%B7%E8%BE%BE%EF%BC%88%E9%9D%A2%E7%A7%AF%EF%BC%89%E5%9B%BE-%E9%AB%98%E6%B8%85.html

源文件下载地址: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):雷达(面积)图的更多相关文章

  1. canvas图表详解系列(1):柱状图

    本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...

  2. canvas图表详解系列(2):折线图

    本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...

  3. canvas图表详解系列(3):动态饼状图(原生Js仿echarts饼状图)

    本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...

  4. canvas图表详解系列(4):动态散点图

    本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...

  5. 【转】Android Canvas绘图详解(图文)

    转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文) 泡 ...

  6. JDBC详解系列(二)之加载驱动

    ---[来自我的CSDN博客](http://blog.csdn.net/weixin_37139197/article/details/78838091)---   在JDBC详解系列(一)之流程中 ...

  7. JDBC详解系列(三)之建立连接(DriverManager.getConnection)

      在JDBC详解系列(一)之流程中,我将数据库的连接分解成了六个步骤. JDBC流程: 第一步:加载Driver类,注册数据库驱动: 第二步:通过DriverManager,使用url,用户名和密码 ...

  8. Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送

    Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送, ...

  9. Android高效率编码-第三方SDK详解系列(二)——Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能

    Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 我的本意是第二篇写Mob的shareSD ...

随机推荐

  1. 扫雷游戏制作过程(C#描述):第一节、创建项目

    前言 起初做扫雷是同学在做,我也跟着做了.做的比较low,其实第一次做这种东西,自己对自己的要求也不高,注重在了解一下,一个app应用程序是怎么产生的..net开发平台,用c#敲的.建议大家一些不懂的 ...

  2. 201521123062《Java程序设计》第6周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 2. 书面作业 Q1.clone方法 1.1 Object ...

  3. 201521123088《java程序设计》第三周学习总结

    1. 本周学习总结 本周学习了关于Java的封装,所谓封装就是将属性私有化,提供公有的方法访问私有属性 2. 书面作业 代码阅读 public class Test1 { private int i ...

  4. 201521123028 《Java程序设计》第13周学习总结

    本周学习总结 书面作业 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? Ans:cec.jmu.edu ...

  5. Python的自学之路:Python基础(一)

    声明:我写博客不是为了什么,只是为了记录自己的学习状态,学过的知识点!方便以后进行好的复习!python小白,勿喷 python环境的搭建,在这里就不细说了,这里有我的链接,可以参考一下:https: ...

  6. Day-18: 电子邮件

    ---恢复内容开始--- 假设要从**@163.com发送邮件到**@sina.com,会经过下面几个过程: 首先,你得使用邮件代理软件(也就是MUA:Mail User Agent),例如Outlo ...

  7. Socket类 以及 ServerSocket类 讲解

    Socket类 套接字是网络连接的端点,套接字使应用可以从网络中读取数据,可以向网络中写入数据.不同计算机上的两个应用程序可以通过连接发送或接收字节流,以此达到相互通信的目的. 为了从一个应用程序向另 ...

  8. multimap 和priority_queue详解

    上一期是关于STL和并查集结合的例题,也附了STL中部分容器的使用摘要,由于是从网上东拼西凑的,感觉有的关键点还是没解释清楚,现在从其中摘出两个容器,用例题对它们的用法进行进一步解释. 以下是例题的介 ...

  9. IDEA用maven创建springMVC项目和配置

    工具准备:IDEA2016.3 Java jdk 1.8 1.DEA创建项目 新建一个maven project,并且选择webapp原型.  然后点击next  这里的GroupId和Artifac ...

  10. ASP.NET Core 认证与授权[2]:Cookie认证

    由于HTTP协议是无状态的,但对于认证来说,必然要通过一种机制来保存用户状态,而最常用,也最简单的就是Cookie了,它由浏览器自动保存并在发送请求时自动附加到请求头中.尽管在现代Web应用中,Coo ...