雷达(面积)图

本章建议学习时间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. 201521123115 《Java程序设计》第3周学习总结

    Java 第三周总结 1.本周学习总结 {{uploading-image-747934.png(uploading...)}} 2.书面作业 1.代码阅读 public class Test1 { ...

  2. Rabbitmq集群安装配置

    Rabbitmq集群安装与配置 一.rabbitmq安装环境准备 1.安装环境准备 这里,我们以两个节点为例进行安装,一个节点为内存节点,另一个节点为硬盘节点,具体可根据自己需要分配节点. 安装系统 ...

  3. Sql Server——基础

    前言: 在了解数据库之前,我们应该首先了解一下和数据库有关的知识,如:什么是数据,什么又是数据库等.  数据:描述事物的符号记录称为数据,它是数据库中存储的基本对象.  数据库(Datebase):数 ...

  4. 06jQuery-01-基本选择器

    1.jQuery概要 JavaScript的一个库,只是一个jquery-xxx.js的文件,它可以让你写更少的代码,做更多的事. $是著名的jQuery符号.实际上,jQuery把所有功能全部封装在 ...

  5. websphere部署--web应用-以自己的项目为例

    启动websphere: 1) 启动Manager: /home/wasadmin/IBM/WebSphere/AppServer/bin/startManager.sh 2) 启动Node:     ...

  6. 我的Java设计模式-工厂方法模式

    女朋友dodo闹脾气,气势汹汹的说"我要吃雪糕".笔者心里啊乐滋滋的,一支雪糕就能哄回来,不亦乐乎?! 但是,雪糕买回来了,她竟然说"不想吃雪糕了,突然想吃披萨" ...

  7. Spring c3p0连接池无法释放解决方案

    通过c3p0配置连接池的时候,在进行压力测试的时候,日志出现了这样一个错误:Data source rejected establishment of connection, message from ...

  8. day16<集合框架+>

    集合框架(去除ArrayList中重复字符串元素方式) 集合框架(去除ArrayList中重复自定义对象元素) 集合框架(LinkedList的特有功能) 集合框架(栈和队列数据结构) 集合框架(用L ...

  9. Minutes和TotalMinutes的区别

    今天测试提了一个BUG,说是消息提醒的时机不对,设置的提前2小时,还没到就提醒了. 看了下代码 (m.ExpectReceiveTime - DateTime.Now).Minutes < (p ...

  10. 第4章 同步控制 Synchronization ----信号量(Semaphore)

    许多文件中都会提到 semaphores(信号量),因为在电脑科学中它是最具历史的同步机制.它可以让你陷入理论的泥淖之中,教授们则喜欢问你一些有关于信号量的疑难杂 症.你可能不容易找到一些关于 sem ...