简单的canvas翻角效果

因为工做需求 , 须要写一个翻角效果;
翻角效果图css

demo连接canvas

右上角须要从无的状态撕开一个标记 , 且有动画过程 , 上图是实现的效果图 , 不是gifapi

对这个翻角效果的难点在于没有翻开的时候露出的是dom下面的内容 , 实现角度来讲 纯dom + css动画的设计方案并无相出一个好的对策 ; 因而捡起了很久以前学的入门级别的canvas;dom

下面说一下实现思路:函数

  1. 动画拆分 :
    将此动画分解成两部分 , 一部分是翻页出现的黑色三角区域 , 另外一个是露出的橘色展现内容
    对于橘色的展现内容区域相对好一些 , 由于是一个规则图形 , 而黑色区域相对较难;工具

先从基础canvas使用方法提及 :布局

<div class="container">
    <canvas class="myCanvas" width="100" height="100"></canvas>
</div>

布局如上 , 这里要说一点踩过的坑是 , canvas必需要设置上width 与 height , 此处并不是为css中的width与height;而是写在dom上的属性 ; 由于dom上的width与height标识了canvas的分辨率(我的理解); 因此此canvas画布分辨率为100*100 , 而展现尺寸是能够经过css控制;字体

js中首先要作的是获取canvas对象 ,动画

var canvas = document.querySelector('.myCanvas'); //获取canvas对应dom
var ctx = canvas.getContext('2d'); //此方法较为基础 , 意为获取canvas绘画2d内容的工具(上下文)
var cw = 100; //分辨率 , 其实直接从dom上获取可能更好些
var ch = 100; //分辨率 , 其实直接从dom上获取可能更好些

ctx这个绘画上下文在这个教程中起到的做用相当重要 ; 它提供了很是强大的api , 好比用于画线 , 填充 , 写文字等 , 这样看来理解为画笔会更为简明一些;spa

此处效果须要用到的api以下 ( 不作详细解释 , 可w3c自行查询 );

ctx.save() //保存上下文状态 (好比画笔尺寸 颜色 旋转角度)
ctx.restore() //返回上次保存的上下文状态
ctx.moveTo(x,y) //上下文移动到具体位置
ctx.lineTo(x,y) //上下文以划线的形式移动到某位置
ctx.stroke() // 画线动做
ctx.quadraticCurveTo() //上下文(画笔)按贝塞尔曲线移动(简单理解为可控的曲线便可)
ctx.arc() //画圆
ctx.beginPath() //开启新的画笔路径
ctx.closePath() //关闭当前画笔路径
ctx.createLinearGradient() //建立canvas渐变对象
ctx.fill() //对闭合区域进行填充
ctx.globalCompositeOperation //画笔的重叠模式

可能方法列举的不够详尽 , 见谅.

首先是绘制黑色翻出的部分 , 图形分解为以下几部分(请根据上图脑补)

  1. 左上角向右下的半弧 ╮

  2. 而后是竖直向下的竖线 |

  3. 而后是向右的半圆 ╰

  4. 再而后是向右的横线

  5. 接着仍是向右下的半弧 ╮

  6. 最后是将线链接会起点

因而第一步 咱们要先将画笔移动到 起始位置

ctx.moveTo(50,0);

而后

ctx.quadraticCurveTo(55 , 5 , 55 , 25); // 能够理解为从(50,0)这个点划线到(55,25)这个点 , 中间会受到(55,5)这个点将直线想磁铁同样"吸"成曲线;

因而第一个向右下的半弧完成 , 此时canvas上没有任何绘制内容 , 由于尚未执行过绘制方法例如stroke或fill,

接下来直线向下就是简单的移动

ctx.lineTo(55 , 40);

这个时候咱们接下来应该画向右的半圆 , 这个时候再用贝塞尔曲线绘制 实在有些不太合适 , 由于从图上来看 , 这里彻底是1/4的圆 , 因此要使用canvas提供的画圆的api

ctx.arc(60 , 40 , 5 , Math.PI , Math.PI / 2 , true);

上述画圆的代码意为 : 以(60,40)点为圆心 , 5为半径 , 逆时针从 180度绘制到90度 , 180度就是圆心的水平向左 到达点(55,40) , 与上一步链接上 , 而后又由于屏幕向下为正 , 90度在圆心正下方 , 因此绘制出此半圆

因而按照相同的步骤 水平向右

ctx.lineTo(75 , 45);

而后再次使用贝塞尔曲线用第一步的思路画出向右下的弧;

ctx.quadraticCurveTo( 95 , 45 , 100 , 50 );

同理 上述贝塞尔曲线能够理解为一条从( 75 , 45 ) 到 ( 100 , 50 )的线被 ( 95 , 45 )"吸"成曲线

最后连接起点 , 闭合绘画区域

ctx.lineTo(50 , 0);

这个时候黑色区域的翻页就画完了 , 而后此时开始填充颜色 ;

var gradient = ctx.createLinearGradient(50 , 50 , 75 , 75);
gradient.addColorStop(0 , '#ccc');
gradient.addColorStop(0.7 , '#111');
gradient.addColorStop(1 , '#000');

咱们经过上述代码建立一个 从( 50 , 50 )点到(75 , 75)点的线性渐变 , 颜色从 #ccc 到 #111 到 #000 ; 建立高光效果;
而后填充:

ctx.fillStyle = gradient;
ctx.fill();

因而翻页效果的一半就算完成了。

至此 , 我要说一点我领悟的canvas的绘画"套路";

对于上述教程中 , 有一步咱们使用了一个词叫作 闭合 , 闭合的概念在canvas中是真是存在的 , 对于fill方法来讲 填充的区间是有一个空间尺寸才能够的 , 好比咱们绘画的这个黑色的三角形 , 加入咱们最后没有将终点与起点相链接 , 一样canvas会自动帮咱们连接最后一笔绘画的位置到起点 , 强制行程闭合空间 , 而这样咱们想再多画几个新的闭合空间就麻烦了 , 因此canvas提供了以下api 新建闭合路径:

ctx.beginPath(); //新建路径
ctx.closePath(); //闭合路径

因此对于咱们接下来要绘制右上角橘色区域来讲 , 咱们在绘制黑色区域以前首先要作的是

ctx.beginPath();
...

而后在fill以前 咱们应该

ctx.closePath();

也就是说beginPath 到 closePath之间标识着咱们本身的一个完整的绘画阶段.

那么接下来绘制右上角的橘色区域就简单不少了:

ctx.beginPath();
ctx.moveTo(50,0);
ctx.lineTo(100,50);
ctx.lineTo(100,0);
ctx.lineTo(50,0);
ctx.closePath();
ctx.fillStyle = '#ff6600';
ctx.fill();

因而右上角的橘色区域咱们就绘制完成了;

文字绘制

接下来绘制"new" , 其实是使用canvas简单的文本绘制 , 代码以下:

var deg = Math.PI / 180;
ctx.globalCompositeOperation = 'source-atop'; //canvas层叠模式
ctx.beginPath();
ctx.font = '14px Arial'; //设置字体大小 字体
ctx.textAlign = 'center'; // 字体对齐方式
ctx.translate(78 , 22);  // 移动canvas画布圆点
ctx.rotate(45 * deg);    // 旋转画布
ctx.fillStyle = '#fff';  // 设置文字颜色
ctx.fillText('NEW' , 0 , 0); //文字绘制动做
ctx.closePath();

对于上述代码中 , 文字的相关api是属于没有难度的 , 只是设置而已 , 须要理解的部分在于 translate和rotate,

这两个方法中 translate的意思为移动canvas画布的( 0 , 0 )点到 (78,22),而后旋转45度, 再将文字渲染在原点 , 实际就是 ( 78 , 22 ) 这个点上, 此时咱们对canvas的画笔作出了很是大的修改

好比咱们修改了旋转角度以及画布圆点 , 这种操做或许只在咱们须要绘制倾斜的new 的时候须要 , 后期可能就不须要使用了 ,

还好canvas的画笔是存在"状态"的, 经过ctx.save();能够保存当前画笔的状态 , 经过ctx.restore();能够恢复到上次画笔保存的状态.

因而我我的理解到 , 在开发canvas动画时 , 一个较好的习惯就是 , 在beginPath以前先ctx.save();保存画笔状态 , 在closePath后ctx.restore();恢复以前的画笔状态 , 这样咱们的每个绘制阶段对于画笔的修改都将是不会有影响的.( 我的经验 )

ctx.globalCompositeOperation = 'source-atop'; //canvas层叠模式

代码中这部分是指 咱们绘制的文字new 与 橘色三角形区域的重叠关系 , 此方法取值较多 , 此处不作过多介绍 , source-atop值可使重叠区域保留 , 新绘制的内容在重叠区域之外的部分消失 , 以此达到new在里面的效果

到这里咱们就开发好了翻角效果的彻底展现的状态 , 那么如何让这个区域动起来呢?

此处须要使用h5提供的用于刷帧的函数 requestAnimationFrame ;

此方法可简单理解为 16毫秒的定时器 , 可是厉害的是能够再各个环境中自动匹配到可达到的相对顺畅的帧率 , 实际并非定时器哈~

咱们须要在这个循环执行的函数中 , 将上述的绘制内容重复绘制 , 例如 :

function draw(){
    drawMethod(); //绘制三角等内容
    window.requestAnimationFrame(function(){
        draw();
    })
}
function drawMethod(){
    //...
}

这样咱们就能够达到刷帧的效果了 , 因而接着咱们要作的就是控制绘制时各个数值的参数.

好比咱们是以 (50,0)为起点 , ( 100 , 50 )为终点这样的两个移动点为绘制标记的 , 若是咱们将两个点进行存储 , 而且每次执行drawMethod的时候更新点的位置 , 而后清空canvas ,再绘制新的点 那么就能够达到canvas动起来的目的了;

实际效果连接在这里

在上面的demo连接中 , 本身定义了一个速度与加速度的关系 , 好比每次绘制一次canvas后 , 将存储的点坐标进行增长一个speed值 , 而后speed值也增长 , 这样speed对应的概念就是速度 , 而speed的增长值对应的就是加速度. 因此就呈现了一种加速运动的状态;

以上内容纯属我的理解内容 , 若果有哪里理解错了 欢迎各位大大指点 , 另demo连接失效可私信.

相关文章
相关标签/搜索