使用H5 canvas绘制的可交互扇形javascript
现有动画实现方式的不足css
setTimeout
和setInterval
都不十分精确。为它们传入的第二个参数,实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。若是队列前面已经加入了其余任务,那动画代码就要等前面的任务完成后再执行。html
css3动画有局限性,好比不是全部属性都能参与动画、动画缓动效果太少、没法彻底控制动画过程等。java
requestAnimationFrame()的优点css3
它告诉浏览器某些JavaScript代码将要执行动画,浏览器能够再运行某些代码后进行适当的优化,十分精确,没有css3的局限问题,可对全部属性操做,动画缓动效果能够依据缓动公式,十分丰富。web
requestAnimationFrame()
就是为了绘制canvas而生,再合适不过了。canvas
代码实现数组
var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame; function updateProgress() { var div = document.getElementById("status"); div.style.width = (parseInt(div.style.width, 10) + 5) + "%"; if(div.style.left != "100%") { requestAnimationFrame(uploadProgress); } } requestAnimationFrame(uploadProgress);
这里展现高级浏览器版本,兼容版请自行google。浏览器
当初学习的时候的文章找不到了,大体的理解是:时间间隔一直,每一个间隔运行的距离不一样。css3动画
//iteration当前执行次数 //startValue执行开始的位置 //changeValue须要执行到的最终位置 //totalIterations须要执行的总次数 easing.easeOutBounce(iteration, startValue, changeValue, totalIterations);
看上面的参数能了解到,easing产生的是与直线的偏移,iteration表示的是偏移的延续,totalIterations表示的动画进行速度,startValue表示的是偏移的起始,changeValue表示的是偏移的量。
用到的一些canvas方法:
fillRect():在画布上绘制的矩形会填充指定颜色,由fillStyle属性指定
strokeRect():在画布上绘制的矩形会使用指定的颜色描边,由strokeStyle属性指定
clearRect():清除画布上的矩形区域
arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x, y)为圆心绘制一条弧线,弧线半径为radius,起始和结束角度(用弧度表示)分别为startAngle和endAngle。最后一个参数表示是否按逆时针方向计算,值为false表示顺时针方向计算
lineTo(x, y):从上一点开始绘制一条直线,到(x, y)为止
drawImage(image, x, y, width, height):绘制图像到画布上,参数有3种,不一一介绍
save()与restore():保存上下文环境,操做...,恢复上次保存的上下文环境
这里只用到了这些,其余方法之后再介绍
为了能更酷炫点,再加上css3的3D翻转效果
transform-style:指定嵌套元素如何在3D空间中呈现。它主要有两个属性值:flat和preserve-3d,它自己须要设置在父元素中,若是设置了transform-style值为preserve-3d,就不能设置overflow值为hidden
perspective:设置查看者的位置,并将可视内容映射到一个视锥上,继而投到一个2D视平面上,就是视距
perspective-origin:决定perspective属性的源点角度
transition:过渡效果
translateZ():使一个元素在三维空间移动
rotateY():指定一个元素围绕Y轴旋转,旋转的量被定义为指定的角度;若是值为正值,元素围绕Y轴顺时针旋转;反之,若是值为负值,元素围绕Y轴逆时针旋转
这里只用到了这些,不作详细介绍,太多了...
准备工做先进行到这里,接下来进行本例的讲解。
参数数组
value:所占比重,百分之几
color:选中时颜色
highlight:选中时鼠标悬停时颜色
grey:未选中时颜色
greylight:未选中时鼠标悬停时颜色
我本身设置传入的参数:
var pieData = [ { value: 0.32, color:"#E8264b", highlight: "#FF0049", grey: "#5B5B5B", greylight: "#333" }, { value: 0.13, color: "#E64261", highlight: "#FF5A5E", grey: "#666", greylight: "#333" }, { value: 0.13, color: "#E05070", highlight: "#FF5A5E", grey: "#727272", greylight: "#444" }, { value: 0.1, color: "#E05D7D", highlight: "#FF5A5E", grey: "#7F7F7F", greylight: "#444" }, { value: 0.09, color: "#DB7691", highlight: "#FF5A5E", grey: "#8E8E8E", greylight: "#666" }, { value: 0.09, color: "#D6829C", highlight: "#FF5A5E", grey: "#999", greylight: "#666" }, { value: 0.07, color: "#D497AA", highlight: "#FF5A5E", grey: "#A5A5A5", greylight: "#666" }, { value: 0.07, color: "#D497AA", highlight: "#FF5A5E", grey: "#A5A5A5", greylight: "#666" } ];
绘制圆盘
function drawing (ctx, i) {//传入canvas的context startValue = endValue;//每一个扇形开始绘制的位置 endValue = startValue + Math.PI * pieData[i].value * 2;//每一个扇形结束绘制的位置 ctx.beginPath();//开始绘制 ctx.arc(225, 225, radiusBig, startValue, endValue, false);//绘制扇形的弧线 ctx.lineTo(225,225);//绘制扇形连接圆心的两条直线 ctx.lineWidth = 2;//设置线的宽度 ctx.closePath();//结束绘制 ctx.fillStyle = pieData[i].grey;//设置扇形颜色 ctx.strokeStyle = "#fff";//设置线的颜色 ctx.fill();//填充 ctx.stroke();//描边 }
绘制文字及其位置
putIcon()用来计算绘制位置,r为半径,θ为角度,x = r + r sinθ, y = r - r cosθ,left和top的值为x和y。
(先写在这,本人不会画图,等学会再来画)
function drawThing(ctx) { var i = 0; var icon = undefined; for( ; i < pieLen ; i++ ) { drawing(ctx, i); } for(i = 0 ; i < pieLen ; i++ ) { if( !effects[i].clicked ) { icon = putIcon(i, 225, 140); ctx.font = "bold 30px Arial"; ctx.textAlign = "center"; ctx.fillStyle = "#fff"; ctx.fillText(i + 1, icon.x, icon.y); } } } function putIcon(count, radiusW, radiusN) { var values = angle = i = 0; for( ; i < count; i++) { values += pieData[i].value; } angle = Math.PI * 2 * (values + pieData[count].value / 2); return { x: Math.floor(radiusW + Math.sin(angle) * radiusN), y: Math.floor(radiusW - Math.cos(angle) * radiusN) } }
肯定交互区域
肯定交互区域本人的思路是获取鼠标在视口上的(x ,y),再将这个点是不是可交互区域,能耗可能会比较大,没想到更好的作法,不过看到css3的clip-path属性能够实现相似效果,以后会研究下。
首先肯定点击区域为外层大圆与内层小圆之间,公式:(x - r) (x - r) + (y - r) (y - r) = r * r;
直线方程:(x - x1)/(x2 - x1) = (y - y1)/(y2 - y1);
两点便可判断一条直线,先肯定圆心点(r, r),再根据角度肯定直线与圆交点(r + r sinθ, y = r - r cosθ)
获得的直线方程为:y = (x - r) (-r cosθ) / (r * sinθ) + r;
相邻两条直线创建二元一次不等式组,便可肯定中间区域;
动画缓动
将easing与requestAnimationFrame()的结合使用,这是实现掉落效果的动画
function clickThing (ctx, i) { var iteration = 0; var totalIterations = 30; var backX, backY; var icon = putIcon(i, 225, 140, true); var ty = icon.y - 25; //当即执行的递归方法 (function miniIcon () { ctx.clearRect(0, 0, 500, 500); backY = easing.easeOutBounce(iteration, ty, 25, totalIterations); ctx.font = "bold 30px Arial"; ctx.textAlign = "center"; ctx.fillStyle = "#fff"; ctx.fillText(i + 1, icon.x, backY); if(iteration < totalIterations) { iteration++; requestAnimationFrame(function () { miniIcon(); }); } })(); }
使用css3实现3D翻转效果
最外层设置视距perspective: 2000px;perspective-origin:right top;
父级设置transition: all 0.7s ease-out;transform-style: preserve-3d;子级设置left和top为自身高宽的一半,使圆心位置为翻转中心点,back-c为背面,front-c为正面,改变rotatey(0deg)为rotatey(-180deg)表示从正面翻转180度到背面,反之亦然,translateZ()在这里用来表示层叠关系,一层盖在另外一层上面。
.wrap { perspective: 2000px; perspective-origin:right top; position: relative; width: 450px; height: 450px; } .wrap .wrap-box { transition: all 0.7s ease-out; transform-style: preserve-3d; position: absolute; top: 50%; left: 50%; } #back-c { position: absolute; top: -225px; left: -225px; transform: translateZ(1px) rotatey(0deg); } #white-c { position: absolute; top: -225px; left: -225px; transform: translateZ(-2px) rotatey(0deg); } #front-c { position: absolute; top: -225px; left: -225px; transform: translateZ(-1px) rotatey(-180deg); }
html内容
写了不少canvas,white-c是翻转以后盖在上面的白色小圆,每次绘制都要画一次,因此拿出来减小能耗,text-c也是出于这个缘由,text-c用来绘制小动画,line-c是拿出来当触发器用的,不必单拎出来,只是想区分用途才拿出来的。
<div class="content"> <div class="wrap"> <div class="wrap-box"> <canvas id="back-c" height="450" width="450"></canvas> <canvas id="front-c" height="450" width="450"></canvas> <canvas id="white-c" height="450" width="450"></canvas> </div> </div> <canvas id="text-c" height="450" width="450"></canvas> <canvas id="line-c" height="450" width="450"></canvas> </div>
花了点时间看了下本身的代码,找寻下迷失的本身,继续启程。
感兴趣的看官点击这里:coding:circle
本文转载自笔者的我的博客:Gaoxuefeng's Blog