• H5扇形


    使用H5 canvas绘制的可交互扇形

    requestAnimationFrame()

    现有动画实现方式的不足

    setTimeoutsetInterval都不十分精确。为它们传入的第二个参数,实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行。

    css3动画有局限性,比如不是所有属性都能参与动画、动画缓动效果太少、无法完全控制动画过程等。

    requestAnimationFrame()的优势

    它告诉浏览器某些JavaScript代码将要执行动画,浏览器可以再运行某些代码后进行适当的优化,十分精确,没有css3的局限问题,可对所有属性操作,动画缓动效果可以依据缓动公式,十分丰富。

    requestAnimationFrame()就是为了绘制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。

    caniuse1


    easing缓冲动画

    当初学习的时候的文章找不到了,大致的理解是:时间间隔一直,每个间隔运行的距离不同。

    //iteration当前执行次数
    //startValue执行开始的位置
    //changeValue需要执行到的最终位置
    //totalIterations需要执行的总次数
    
    easing.easeOutBounce(iteration, startValue, changeValue, totalIterations);

    看上面的参数能了解到,easing产生的是与直线的偏移,iteration表示的是偏移的延续,totalIterations表示的动画进行速度,startValue表示的是偏移的起始,changeValue表示的是偏移的量。


    canvas方法

    用到的一些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

    为了能更酷炫点,再加上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;

    相邻两条直线建立二元一次不等式组,即可确定中间区域;

    circle3

    动画缓动

    将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;
         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

  • 相关阅读:
    ios开发 <AppName>-Prefix.pch文件的用法详解
    iOS Block全面分析
    _weak typeof(self) weakSelf = self
    判断当前iOS设备的方法
    修改UITextfield的Placeholder字体的颜色
    uibutton实现左文字右图片
    apache Apache winnt_accept: Asynchronous AcceptEx failed 错误的解决
    android4.0 锁屏实现(转)
    android 代码设置、打开wifi热点及热点的连接(转)
    tomcat arp
  • 原文地址:https://www.cnblogs.com/10manongit/p/12943861.html
Copyright © 2020-2023  润新知