简单的 canvas 翻角效果

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

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

下面说一下实现思路:

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

先从基础canvas使用方法说起 :

1

2

3

<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对象 ,

1

2

3

4

var canvas = document.querySelector('.myCanvas'); //获取canvas对应dom

var ctx = canvas.getContext('2d'); //此方法较为基础 , 意为获取canvas绘画2d内容的工具(上下文)

var cw = 100; //分辨率 , 其实直接从dom上获取可能更好些

var ch = 100; //分辨率 , 其实直接从dom上获取可能更好些

ctx这个绘画上下文在这个教程中起到的作用至关重要 ; 它提供了非常强大的api , 比如用于画线 , 填充 , 写文字等 , 这样看来理解为画笔会更为简明一些;

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

1

2

3

4

5

6

7

8

9

10

11

12

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. 最后是将线连接会起点

于是第一步 我们要先将画笔移动到 起始位置

1

ctx.moveTo(50,0);

然后

1

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

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

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

1

ctx.lineTo(55 , 40);

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

1

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

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

于是按照相同的步骤 水平向右

1

ctx.lineTo(75 , 45);

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

1

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

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

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

1

ctx.lineTo(50 , 0);

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

1

2

3

4

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 ; 创建高光效果;
然后填充:

1

2

ctx.fillStyle = gradient;

ctx.fill();

于是翻页效果的一半就算完成了。

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

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

1

2

ctx.beginPath(); //新建路径

ctx.closePath(); //闭合路径

所以对于我们接下来要绘制右上角橘色区域来说 , 我们在绘制黑色区域之前首先要做的是

1

2

ctx.beginPath();

...

然后在fill之前 我们应该

1

ctx.closePath();

也就是说beginPath 到 closePath之间标识着我们自己的一个完整的绘画阶段.

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

1

2

3

4

5

6

7

8

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简单的文本绘制 , 代码如下:

1

2

3

4

5

6

7

8

9

10

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的画笔做出了非常大的修改


猜你喜欢

转载自blog.51cto.com/13959004/2178104