js canvas仿支付宝芝麻信用分仪表盘
这是一个仿支付宝芝麻信用分的一个canvas,其实就是一个动画仪表盘。
首先, 上原图:
这个是在下支付宝上的截图,分低各位见笑了。然后看下我用canvas实现的效果图:
<canvas id="canvas" width="400" height="700" data-score='724'></canvas> <!-- 设置data-score,分数区间[400, 900] -->
唉,总感觉不像。这个是GIF图,可能在网页上打开的效果会好一点(当然可能就是这样)。大家可以点击底部预览codepen上的演示。有两个不完美的地方,一个是实际上芝麻信用表盘上的的刻度是不均匀的,我这为了简单的实现就采取相同的刻度;二是表盘上运动的点是有模糊的效果,还没解决。唉,下次再说吧。
接下来还是来说说怎么实现的吧。第一步,国际惯例,创建画布:
var canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), cWidth = canvas.width, cHeight = canvas.height;
然后绘制表盘,虽说不是处女座,但也要尽可能做到跟原图上的一样,那就是这个环形开口的角度是多少呢?请上ps来测一下:
嗯,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呢?那就要用到传说中三角函数了。
通过上图我们可以得到
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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相关文章
- 本篇文章主要分享了通过window.navigator来判断浏览器及其版本信息的实例代码。具有一定的参考价值,下面跟着小编一起来看下吧...2017-01-23
- 这篇文章主要介绍了js如何实现浏览器打印功能,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-15
- 这篇文章主要给大家介绍了关于Nest.js参数校验和自定义返回数据格式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-28
- 下面小编就为大家带来一篇利用JS实现点击按钮后图片自动切换的简单方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-10-25
- 作为前端,一直以来都知道HTTP劫持与XSS跨站脚本、CSRF跨站请求伪造。防御这些劫持最好的方法是从后端入手,前端能做的太少。而且由于源码的暴露,攻击者很容易绕过防御手段。但这不代表我们去了解这块的相关知识是没意义的,本文的许多方法,用在其他方面也是大有作用。...2021-05-24
- 这篇文章主要为大家详细介绍了js+css实现回到顶部按钮back to top回到顶部按钮,感兴趣的小伙伴们可以参考一下...2016-03-03
- 那么今天我就用JavaScript代码来实现这个效果吧,那么首先介绍一下整个的思路,首先我们先将确定输入密码的位数,我的需求是5位,那么就用一个div标签包住5个input标签...2016-01-02
- 这篇文章主要为大家详细介绍了js实现上传图片及时预览的相关资料,具有一定的参考价值,感兴趣的朋友可以参考一下...2016-05-09
- 这篇文章主要介绍了js实现调用网络摄像头及常见错误处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-07
- 这篇文章主要为大家详细介绍了JS实现随机生成验证码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-06
- 这篇文章主要介绍了js组件SlotMachine实现图片切换效果制作抽奖系统的相关资料,需要的朋友可以参考下...2016-04-19
- Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统.这篇文章主要介绍了vue.js 表格分页ajax 异步加载数据的相关资料,需要的朋友可以参考下...2016-10-20
- 为了网站的安全性,很多朋友都把密码设的比较复杂,但是如何密码不能明显示,不知道输的是对是错,为了安全起见可以把密码显示的,那么基于js代码如何实现的呢?下面通过本文给大家介绍JavaScript实现表单密码的隐藏和显示,需要的朋友参考下...2016-03-03
- 这篇文章主要为大家详细介绍了js实现列表按字母排序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-11
- 这篇文章主要介绍了基于JavaScript实现文字超出部分隐藏 的相关资料,需要的朋友可以参考下...2016-03-01
- 这篇文章主要介绍了JS实现响应鼠标点击动画渐变弹出层效果代码,具有非常自然流畅的动画过度效果,涉及JavaScript针对鼠标事件的响应及页面元素样式的动态操作相关技巧,需要的朋友可以参考下...2016-03-28
- 这篇文章主要给大家介绍了一个关于JS正则匹配的踩坑记录,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-13
- 这次文章要给大家介绍的是node.JS md5加密中文与php结果不一致怎么办,不知道具体解决办法的下面跟小编一起来看看。 因项目需要,需要Node.js与PHP做接口调用,发现nod...2017-07-06
- 系统的学习了一下angularjs,发现angularjs的有些思想根php的模块smarty很像,例如数据绑定,filter。如果对smarty比较熟悉的话,学习angularjs会比较容易一点,这篇文章给大家介绍angularjs filter用法详解,感兴趣的朋友一起学习吧...2015-12-29
- 本文给大家介绍的是nodejs实现使用阿里大鱼短信API发送消息的方法和代码,有需要的小伙伴可以参考下。...2016-01-20