使用canvas實現(xiàn)數(shù)據(jù)可視化
可視化的意義是幫助人更好的分析數(shù)據(jù)喉脖,信息的質(zhì)量很大程度上依賴于其表達(dá)方式夸楣。對數(shù)字羅列所組成的數(shù)據(jù)中所包含的意義進(jìn)行分析宾抓,使分析結(jié)果可視化。
1.條形圖
請看代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.container {
padding: 0 50px;
}
header>input {
width: 300px;
height: 30px;
margin: 10px;
font-size: 18px;
}
canvas {
border: 1px solid;
}
</style>
</head>
<body>
<div class="container">
<header>
<input type="text" id="inp">
</header>
<canvas width="800" height="500" id="canvas"></canvas>
</div>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var inp = document.getElementById('inp');
//初始數(shù)組
var csArr = [1, 2, 5, 4, 6, 7, 8, 9];
//記錄每次繪制數(shù)據(jù)的數(shù)組
var dataArr = [];
inp.value = csArr;
PhALL(ctx, csArr)
//繪制所有
function PhALL(ctx, arr) {
//清除畫布
ctx.clearRect(0, 0, 800, 500);
dataArr = [];
//根據(jù)數(shù)組得出矩形寬高和間距
var rectW = (canvas.width - 150) / (arr.length + 1);
var rectJ = rectW / (arr.length - 1);
var rectH = (canvas.height - 100) / Math.max.apply(arr, arr);
for (var j = 0; j < arr.length; j++) {
dataArr.push({
x: 80 + rectW * j + rectJ * j,
y: 439,
w: rectW,
h: rectH * arr[j],
color: '#2D8CF0',
text: arr[j],
textX: rectW / 2.3 + 80 + rectW * j + rectJ * j,
textY: 480,
id: j + 1,
value: csArr[j]
})
}
for (var i = 0; i < arr.length; i++) {
phRect(ctx, dataArr[i]);
phCount(ctx, dataArr[i])
}
phXy();
phArr(ctx, arr)
}
//繪制矩形
function phRect(ctx, obj) {
ctx.beginPath();
ctx.moveTo(obj.x, obj.y);
ctx.lineTo(obj.x + obj.w, obj.y);
ctx.lineTo(obj.x + obj.w, obj.y - obj.h);
ctx.lineTo(obj.x, obj.y - obj.h);
ctx.lineTo(obj.x.w, obj.y);
ctx.fillStyle = obj.color;
ctx.fill();
ctx.closePath();
}
//繪制橫縱坐標(biāo)
function phXy() {
ctx.beginPath();
ctx.moveTo(60, 460);
ctx.lineTo(750, 460);
ctx.stroke();
ctx.moveTo(60, 460);
ctx.lineTo(60, 30);
ctx.stroke();
ctx.closePath();
for (var i = 439; i > 100; i -= 50) {
ctx.beginPath();
ctx.moveTo(60 + 0.5, i + 0.5);
ctx.lineTo(750 + 0.5, i + 0.5);
ctx.strokeStyle = 'rgba(0,0,0,0.6)';
ctx.stroke();
ctx.closePath();
}
}
//下面
function phCount(ctx, obj) {
ctx.font = '15px sans-serif';
ctx.fillText(obj.text, obj.textX, obj.textY);
}
//上面
function phArr(ctx, arr) {
ctx.font = '20px sans-serif';
ctx.fillText(arr, 350, 20)
}
inp.onchange = function () {
if (/^\s*\[\s*([1-9]\d*),([1-9]\d*,)*([1-9]\d*)\s*\]\s*$/.test(this.value)) {
PhALL(ctx, JSON.parse(this.value));
csArr = JSON.parse(this.value);
}
}
canvas.onmousemove = function (e) {
// 清除顏色
for (var j = 0; j < dataArr.length; j++) {
dataArr[j].color = '#2D8CF0';
}
ctx.clearRect(0, 0, 800, 500);
var curentId = 0;
var arrContent = 0;
//改變目標(biāo)顏色
for (var i = 0; i < csArr.length; i++) {
phRect(ctx, dataArr[i]);
phCount(ctx, dataArr[i]);
if (ctx.isPointInPath(e.offsetX, e.offsetY)) {
dataArr[i].color = '#A7BAC2';
curentId = dataArr[i].id;
}
}
//重繪
for (var i = 0; i < csArr.length; i++) {
phRect(ctx, dataArr[i]);
phCount(ctx, dataArr[i]);
}
phArr(ctx, csArr);
phXy();
if (curentId >= 1) {
phRadiuRect(ctx, e.offsetX + 10, e.offsetY - 50, dataArr[curentId - 1])
}
}
function phRadiuRect(ctx, x, y, obj) {
var w = 100;
var h = 80;
var r = 10;
ctx.save();
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arc(w + x - r, y + r, r, 3 / 2 * Math.PI, 2 * Math.PI, false);
ctx.arc(w + x - r, y + h - r, r, 0, 1 / 2 * Math.PI, false);
ctx.arc(x + r, y + h - r, r, 1 / 2 * Math.PI, Math.PI, false);
ctx.arc(x + r, y + r, r, Math.PI, 3 / 2 * Math.PI, false);
ctx.fillStyle = 'rgba(94,100,182,.8)';
ctx.closePath();
ctx.fill();
ctx.fillStyle = 'white';
ctx.font = "15px bold 宋體";
ctx.fillText('該id為:' + obj.id, x + 10, y + 20);
ctx.fillText('元素值為' + obj.value, x + 10, y + 45);
ctx.restore();
}
</script>
</body>
</html>
效果圖片:
2.餅圖
請看代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>數(shù)據(jù)可視化</title>
</head>
<body>
<canvas id="kycanvas" style="display: block;margin: auto;border: 1px solid #666666;">
當(dāng)前瀏覽器不支持canvas豫喧,請更換瀏覽器后再試石洗!
</canvas>
</body>
<script>
var canvas = document.getElementById("kycanvas");
var ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 600;
var r = 100;
var x = 150;
var y = 150;
var arr = [3,4,6,5,2];
var dataArr = returnDataArr(arr);//獲取帶位置信息的數(shù)組
var fnArr = [];
for(var i = 0;i < dataArr.length;i++){//遍歷位置數(shù)組,初始化扇形且保存繪制動作到fnArr
phShan(ctx,dataArr[i]);
fnArr.push({
fn:phShan,
org:dataArr[i]
})
}
canvas.onmousemove = function(e){//鼠標(biāo)滑過重繪扇形
ctx.clearRect(0,0,600,600);
for(var i = 0;i < fnArr.length;i++){
fnArr[i].org.r = r;
fnArr[i].org.newColor = '';
fnArr[i].fn(ctx,fnArr[i].org);
if(ctx.isPointInPath(e.offsetX,e.offsetY)){
fnArr[i].org.newColor = 'red';
fnArr[i].org.r = r+15;
fnArr[i].fn(ctx,fnArr[i].org);
}
}
}
// var sum = new s([1,1,2,3]);
// console.log(sum)
//根據(jù)原始數(shù)組返回帶位置信息的數(shù)組
function returnDataArr(arr){
if(!arr || !Array.isArray(arr) || arr.length==0){
throw new Error('returnDataArr的參數(shù)不合法');
}
var dataArr = [];
var sumArr = returnSumArr(arr);//返回數(shù)組之和
//每一個元素在圓中所占的弧度 arr[i]/sumArr * 2 * Math.PI
for(var i = 0;i < arr.length;i++){
if(i==0){
dataArr.push({
x:x,
y:y,
r:r,
start:0,
newColor:'',
oldColor:returnRadomColor(),
end:arr[i]/sumArr * 2 * Math.PI,
id:i+1,
value:arr[i]
})
}else{
dataArr.push({
x:x,
y:y,
r:r,
newColor:'',
oldColor:returnRadomColor(),
start:dataArr[i-1].end,
end:dataArr[i-1].end+arr[i]/sumArr * 2 * Math.PI,
id:i+1,
value:arr[i]
})
}
}
return dataArr;
}
//繪制一個扇形的函數(shù)
function phShan(ctx,obj){
ctx.save();
ctx.beginPath();
ctx.moveTo(obj.x,obj.y);
ctx.arc(obj.x,obj.y,obj.r,obj.start,obj.end,false);
ctx.closePath();
ctx.fillStyle = obj.newColor?obj.newColor:obj.oldColor;
ctx.fill();
ctx.restore();
}
//求數(shù)組的和
function returnSumArr(arr){
if(!arr || !Array.isArray(arr) || arr.length==0){
return false;
}
var sum = 0;
for(var i = 0;i < arr.length;i++){
sum+=arr[i]
}
return sum;
}
//返回一個隨機色
function returnRadomColor(){
return 'rgba('+(Math.ceil(Math.random()*255))+','+(Math.ceil(Math.random()*255))+','+(Math.ceil(Math.random()*255))+','+Math.random()+')'
}
</script>
效果圖片: