网络编程 
首页 > 网络编程 > 浏览文章

js canvas仿支付宝芝麻信用分仪表盘

(编辑:jimmy 日期: 2024/11/19 浏览:3 次 )

这是一个仿支付宝芝麻信用分的一个canvas,其实就是一个动画仪表盘。

首先, 上原图:

js canvas仿支付宝芝麻信用分仪表盘

这个是在下支付宝上的截图,分低各位见笑了。然后看下我用canvas实现的效果图:

<canvas id="canvas" width="400" height="700" data-score='724'></canvas>
<!-- 设置data-score,分数区间[400, 900] -->

js canvas仿支付宝芝麻信用分仪表盘

唉,总感觉不像。这个是GIF图,可能在网页上打开的效果会好一点(当然可能就是这样)。大家可以点击底部预览codepen上的演示。有两个不完美的地方,一个是实际上芝麻信用表盘上的的刻度是不均匀的,我这为了简单的实现就采取相同的刻度;二是表盘上运动的点是有模糊的效果,还没解决。唉,下次再说吧。

接下来还是来说说怎么实现的吧。第一步,国际惯例,创建画布:

var canvas = document.getElementById('canvas'),
 ctx = canvas.getContext('2d'),
 cWidth = canvas.width,
 cHeight = canvas.height;

然后绘制表盘,虽说不是处女座,但也要尽可能做到跟原图上的一样,那就是这个环形开口的角度是多少呢?请上ps来测一下:

js canvas仿支付宝芝麻信用分仪表盘

嗯,136°,这个角度确实刁钻,为了方便接下来的计算,那就约等于140°。那么一个分数段的弧度就是:

var deg1 = Math.PI * 11 / 45
先把中间半透明的刻度层画好:

ctx.save(); //中间刻度层
ctx.beginPath();
ctx.strokeStyle = 'rgba(255, 255, 255, .2)';
ctx.lineWidth = 10;
ctx.arc(0, 0, 135, 0, 11 * deg0, false);
ctx.stroke();
ctx.restore();

接着,画6条刻度线,用for循环来实现:

ctx.save(); // 刻度线
for (var i = 0; i < 6; i++) {
 ctx.beginPath();
 ctx.lineWidth = 2;
 ctx.strokeStyle = 'rgba(255, 255, 255, .3)';
 ctx.moveTo(140, 0);
 ctx.lineTo(130, 0);
 ctx.stroke();
 ctx.rotate(deg1);
}
ctx.restore();

同理,再把大刻度细分为5个小刻度:

ctx.save(); // 细分刻度线
for (i = 0; i < 25; i++) {
 if (i % 5 !== 0){
 ctx.beginPath();
 ctx.lineWidth = 2;
 ctx.strokeStyle = 'rgba(255, 255, 255, .1)';
 ctx.moveTo(140, 0);
 ctx.lineTo(133, 0);
 ctx.stroke();
 }
 ctx.rotate(deg1 / 5);
}
ctx.restore();

刻度到这里就ok了,还需要给刻度标上文字和每个分数段的信用级别,具体的参见代码,因为跟刻度实现的原理差不多,就不啰嗦了。现在最关键就是实现表盘上那个运动的点(不知道怎么称呼,下文就叫它动点),我们可以这样想,它是个半径很小的圆,只不过是画在最外层环形轨道上圆,而圆在canvas上的实现方法是:

ctx.arc(x, y, radius, sAngle, eAngle, false);
我们只要控制x, y就能让它动起来,实现我们想要的效果。so,创建一个动点对象:

function Dot() {
 this.x = 0;
 this.y = 0;
 this.draw = function (ctx) {
 ctx.save();
 ctx.beginPath();
 ctx.fillStyle = 'rgba(255, 255, 255, .7)';
 ctx.arc(this.x, this.y, 3, 0, Math.PI * 2, false);
 ctx.fill();
 ctx.restore();
 };
}
var dot = new Dot(),
 dotSpeed = 0.03, //控制动点的速度
 angle = 0, //这个很关键,用来得到动点的坐标x, y
 credit = 400; //信用最低分数

如何得到dot的坐标x, y呢?那就要用到传说中三角函数了。

js canvas仿支付宝芝麻信用分仪表盘

通过上图我们可以得到

x = r * cos(angle), y = r * sin(angle)
在JavaScript中,dot的中心坐标就变成了:

dot.x = radius * Math.cos(angle); //radius为最外层轨道的半径值
dot.y = radius * Math.sin(angle);

接下来我们只要得到这个angle。这个通过弧度与分数的比例关系就可以得到:

var aim = (score - 400) * deg1 / 100;
if (angle < aim) {
 angle += dotSpeed;
}
dot.draw(ctx);

然后让中间的信用分数也能随动点的转动而变化,创建一个text(),为了使数字变化能和动点保持一致,要根据动点的速率来计算数字变化:

function text(process) {
 ctx.save();
 ctx.rotate(10 * deg0);
 ctx.fillStyle = '#000';
 ctx.font = '80px Microsoft yahei';
 ctx.textAlign = 'center';
 ctx.textBaseLine = 'top';
 ctx.fillText(process, 0 ,10);
 ctx.restore();
}
var textSpeed = Math.round(dotSpeed * 100 / deg1),
if (credit < score - textSpeed) {
 credit += textSpeed;
} else if (credit >= score - textSpeed && credit < score) {
 credit += 1; // 这里确保信用分数最后停下来是我们输入的分数
}
text(credit);

最后这一切都逃不过让window.requestAnimationFrame()来控制绘制动画和用ctx.clearRect(0, 0, cWidth, cHeight)来清除画布。

写的不好,大家将就着看,我相信大家理解代码的能力一定强于理解我这些我自己都不知道说什么的文字。

好了,以上。

code:

<!DOCTYPE html>
<html>
 
 <head>
 <meta charset="UTF-8">
 <title>芝麻信用仪表盘</title>
 <style type="text/css">
  html,
  body {
  width: 100%;
  height: 100%;
  margin: 0;
  }
  
  canvas {
  border: 1px solid #eee;
  position: relative;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background: -webkit-linear-gradient(top, #0e83f5 0%, #21bdf6 100%);
  background: -ms-linear-gradient(top, #0e83f5 0%, #21bdf6 100%);
  background: -moz-linear-gradient(top, #0e83f5 0%, #21bdf6 100%);
  background: linear-gradient(top, #0e83f5 0%, #21bdf6 100%);
  }
 </style>
 <script type="text/javascript">
  window.onload = function() {
  var canvas = document.getElementById('canvas'),
   ctx = canvas.getContext('2d'),
   cWidth = canvas.width,
   cHeight = canvas.height,
   score = canvas.attributes['data-score'].value,
   stage = ['较差', '中等', '良好', '优秀', '极好'],
   radius = 150,
   deg0 = Math.PI / 9,
   deg1 = Math.PI * 11 / 45;
 
  if(score < 400 || score > 900) {
   alert('信用分数区间:400~900');
  } else {
   var dot = new Dot(),
   dotSpeed = 0.03,
   textSpeed = Math.round(dotSpeed * 100 / deg1),
   angle = 0,
   credit = 400;
 
   (function drawFrame() {
 
   ctx.save();
   ctx.clearRect(0, 0, cWidth, cHeight);
   ctx.translate(cWidth / 2, cHeight / 2);
   ctx.rotate(8 * deg0);
 
   dot.x = radius * Math.cos(angle);
   dot.y = radius * Math.sin(angle);
 
   var aim = (score - 400) * deg1 / 100;
   if(angle < aim) {
    angle += dotSpeed;
   }
   dot.draw(ctx);
 
   if(credit < score - textSpeed) {
    credit += textSpeed;
   } else if(credit >= score - textSpeed && credit < score) {
    credit += 1;
   }
   text(credit);
 
   ctx.save();
   ctx.beginPath();
   ctx.lineWidth = 3;
   ctx.strokeStyle = 'rgba(255, 255, 255, .5)';
   ctx.arc(0, 0, radius, 0, angle, false);
   ctx.stroke();
   ctx.restore();
 
   window.requestAnimationFrame(drawFrame);
 
   ctx.save(); //中间刻度层
   ctx.beginPath();
   ctx.strokeStyle = 'rgba(255, 255, 255, .2)';
   ctx.lineWidth = 10;
   ctx.arc(0, 0, 135, 0, 11 * deg0, false);
   ctx.stroke();
   ctx.restore();
 
   ctx.save(); // 刻度线
   for(var i = 0; i < 6; i++) {
    ctx.beginPath();
    ctx.lineWidth = 2;
    ctx.strokeStyle = 'rgba(255, 255, 255, .3)';
    ctx.moveTo(140, 0);
    ctx.lineTo(130, 0);
    ctx.stroke();
    ctx.rotate(deg1);
   }
   ctx.restore();
 
   ctx.save(); // 细分刻度线
   for(i = 0; i < 25; i++) {
    if(i % 5 !== 0) {
    ctx.beginPath();
    ctx.lineWidth = 2;
    ctx.strokeStyle = 'rgba(255, 255, 255, .1)';
    ctx.moveTo(140, 0);
    ctx.lineTo(133, 0);
    ctx.stroke();
    }
    ctx.rotate(deg1 / 5);
   }
   ctx.restore();
 
   ctx.save(); //信用分数
   ctx.rotate(Math.PI / 2);
   for(i = 0; i < 6; i++) {
    ctx.fillStyle = 'rgba(255, 255, 255, .4)';
    ctx.font = '10px Microsoft yahei';
    ctx.textAlign = 'center';
    ctx.fillText(400 + 100 * i, 0, -115);
    ctx.rotate(deg1);
   }
   ctx.restore();
 
   ctx.save(); //分数段
   ctx.rotate(Math.PI / 2 + deg0);
   for(i = 0; i < 5; i++) {
    ctx.fillStyle = 'rgba(255, 255, 255, .4)';
    ctx.font = '10px Microsoft yahei';
    ctx.textAlign = 'center';
    ctx.fillText(stage[i], 5, -115);
    ctx.rotate(deg1);
   }
   ctx.restore();
 
   ctx.save(); //信用阶段及评估时间文字
   ctx.rotate(10 * deg0);
   ctx.fillStyle = '#fff';
   ctx.font = '28px Microsoft yahei';
   ctx.textAlign = 'center';
   if(score < 500) {
    ctx.fillText('信用较差', 0, 40);
   } else if(score < 600 && score >= 500) {
    ctx.fillText('信用中等', 0, 40);
   } else if(score < 700 && score >= 600) {
    ctx.fillText('信用良好', 0, 40);
   } else if(score < 800 && score >= 700) {
    ctx.fillText('信用优秀', 0, 40);
   } else if(score <= 900 && score >= 800) {
    ctx.fillText('信用极好', 0, 40);
   }
 
   ctx.fillStyle = '#80cbfa';
   ctx.font = '14px Microsoft yahei';
   ctx.fillText('评估时间:2016.11.06', 0, 60);
 
   ctx.fillStyle = '#7ec5f9';
   ctx.font = '14px Microsoft yahei';
   ctx.fillText('BETA', 0, -60);
   ctx.restore();
 
   // ctx.save(); //最外层轨道
   ctx.beginPath();
   ctx.strokeStyle = 'rgba(255, 255, 255, .4)';
   ctx.lineWidth = 3;
   ctx.arc(0, 0, radius, 0, 11 * deg0, false);
   ctx.stroke();
   ctx.restore();
 
   })();
  }
 
  function Dot() {
   this.x = 0;
   this.y = 0;
   this.draw = function(ctx) {
   ctx.save();
   ctx.beginPath();
   ctx.fillStyle = 'rgba(255, 255, 255, .7)';
   ctx.arc(this.x, this.y, 3, 0, Math.PI * 2, false);
   ctx.fill();
   ctx.restore();
   };
  }
 
  function text(process) {
   ctx.save();
   ctx.rotate(10 * deg0);
   ctx.fillStyle = '#000';
   ctx.font = '80px Microsoft yahei';
   ctx.textAlign = 'center';
   ctx.textBaseLine = 'top';
   ctx.fillText(process, 0, 10);
   ctx.restore();
  }
  };
 </script>
 </head>
 
 <body>
 <canvas id="canvas" width="400" height="700" data-score='724'></canvas>
 </body>
 
</html>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

上一篇:微信小程序 获取相册照片实例详解
下一篇:Javascript使用SWFUpload进行多文件上传
一句话新闻
一文看懂荣耀MagicBook Pro 16
荣耀猎人回归!七大亮点看懂不只是轻薄本,更是游戏本的MagicBook Pro 16.
人们对于笔记本电脑有一个固有印象:要么轻薄但性能一般,要么性能强劲但笨重臃肿。然而,今年荣耀新推出的MagicBook Pro 16刷新了人们的认知——发布会上,荣耀宣布猎人游戏本正式回归,称其继承了荣耀 HUNTER 基因,并自信地为其打出“轻薄本,更是游戏本”的口号。
众所周知,寻求轻薄本的用户普遍更看重便携性、外观造型、静谧性和打字办公等用机体验,而寻求游戏本的用户则普遍更看重硬件配置、性能释放等硬核指标。把两个看似难以相干的产品融合到一起,我们不禁对它产生了强烈的好奇:作为代表荣耀猎人游戏本的跨界新物种,它究竟做了哪些平衡以兼顾不同人群的各类需求呢?
友情链接:杰晶网络 DDR爱好者之家 南强小屋 黑松山资源网 白云城资源网 网站地图 SiteMap