canvas仿芝麻信用分仪表盘
rmfi6531
8年前
<p>这是一个仿支付宝芝麻信用分的一个canvas,其实就是一个动画仪表盘。</p> <p>首先, 上原图:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/4f64b928b2710b4ad3f438d5b8d6a663.png"></p> <p>这个是在下支付宝上的截图,分低各位见笑了。然后看下我用canvas实现的效果图:</p> <pre> <code class="language-javascript"><canvas id="canvas" width="400" height="700" data-score='724'></canvas> <!-- 设置data-score,分数区间[400, 900] --> </code></pre> <p style="text-align:center"><img src="https://simg.open-open.com/show/15edc230b87dcc3ff3162bd8af25aadd.gif"></p> <p>唉,总感觉不像。这个是GIF图,可能在网页上打开的效果会好一点(</p> <p>当然可能就是这样</p> <p>)。大家可以点击底部预览codepen上的演示。有两个不完美的地方,一个是实际上芝麻信用表盘上的的刻度是不均匀的,我这为了简单的实现就采取相同的刻度;二是表盘上运动的点是有模糊的效果,还没解决。唉,下次再说吧。</p> <p>接下来还是来说说怎么实现的吧。第一步,国际惯例,创建画布:</p> <pre> <code class="language-javascript">var canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), cWidth = canvas.width, cHeight = canvas.height; </code></pre> <p>然后绘制表盘,虽说不是处女座,但也要尽可能做到跟原图上的一样,那就是这个环形开口的角度是多少呢?请上ps来测一下:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/fb2944e0f94c154c4c844bfb67be35f9.png"></p> <p>嗯,136°,这个角度确实刁钻,为了方便接下来的计算,那就约等于140°。那么一个分数段的弧度就是:</p> <pre> <code class="language-javascript">var deg1 = Math.PI * 11 / 45 </code></pre> <p>先把中间半透明的刻度层画好:</p> <pre> <code class="language-javascript">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(); </code></pre> <p>接着,画6条刻度线,用for循环来实现:</p> <pre> <code class="language-javascript">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(); </code></pre> <p>同理,再把大刻度细分为5个小刻度:</p> <pre> <code class="language-javascript">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(); </code></pre> <p>刻度到这里就ok了,还需要给刻度标上文字和每个分数段的信用级别,具体的参见代码,因为跟刻度实现的原理差不多,就不啰嗦了。现在最关键就是实现表盘上那个运动的点(不知道怎么称呼,下文就叫它动点),我们可以这样想,它是个半径很小的圆,只不过是画在最外层环形轨道上圆,而圆在 canvas 上的实现方法是:</p> <pre> <code class="language-javascript">ctx.arc(x, y, radius, sAngle, eAngle, false); </code></pre> <p>我们只要控制x, y就能让它动起来,实现我们想要的效果。so,创建一个动点对象:</p> <pre> <code class="language-javascript">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; //信用最低分数 </code></pre> <p>如何得到dot的坐标x, y呢?那就要用到传说中三角函数了。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/e4aa3e589e3eed1c82dc786b8bc4bd63.png"></p> <p>通过上图我们可以得到</p> <pre> <code class="language-javascript">x = r * cos(angle), y = r * sin(angle) </code></pre> <p>在JavaScript中,dot的中心坐标就变成了:</p> <pre> <code class="language-javascript">dot.x = radius * Math.cos(angle); //radius为最外层轨道的半径值 dot.y = radius * Math.sin(angle); </code></pre> <p>接下来我们只要得到这个angle。这个通过弧度与分数的比例关系就可以得到:</p> <pre> <code class="language-javascript">var aim = (score - 400) * deg1 / 100; if (angle < aim) { angle += dotSpeed; } dot.draw(ctx); </code></pre> <p>然后让中间的信用分数也能随动点的转动而变化,创建一个 text() ,为了使数字变化能和动点保持一致,要根据动点的速率来计算数字变化:</p> <pre> <code class="language-javascript">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); </code></pre> <p>最后这一切都逃不过让window.requestAnimationFrame()来控制绘制动画和用ctx.clearRect(0, 0, cWidth, cHeight)来清除画布。</p> <p> </p> <p> </p> <p>来自:http://www.cnblogs.com/libin-1/p/6068340.html</p> <p> </p>