视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
HTML5之7__Canvas:缩放、旋转、创建阴影
2020-11-27 15:12:43 责编:小采
文档
 一. canvas API 的scale() 函数用于缩放.

scale() 带有两个参数,分别代表在x, y 两个维度的值, 每个参数在 canvas 显示图像的时候, 向其传递在本方向轴上图像要放大(或缩小) 的量, 如果x为2, 就代表所绘制图像中全部元素都会变成两倍宽, 如果y 值为0.5 ,绘制出来的图像全部元素都会变成之前的一半高。

例如以下程序很方便地在canvas 上创建出新的树.

<!DOCTYPE html>
<html>
<meta charset="UTF-8">
 <title>缩放示例</title>
 <canvas id="trails" style="border: 1px solid;" width="400" height="600"> </canvas>
 <script>
 var gravel = new Image();
 gravel.src = "gravel.jpg";
 gravel.onload = function () {
 drawTrails();
 }

 function createCanopyPath(context) {
 context.beginPath();
 context.moveTo(-25, -50);
 context.lineTo(-10, -80);
 context.lineTo(-20, -80);
 context.lineTo(-5, -110);
 context.lineTo(-15, -110);

 context.lineTo(0, -140);
 context.lineTo(15, -110);
 context.lineTo(5, -110);
 context.lineTo(20, -80);
 context.lineTo(10, -80);
 context.lineTo(25, -50);
 context.closePath();
 }

 // 将绘制树的方法 放到 drawTree(),方便重用
 function drawTree(context) {
 var trunkGradient = context.createLinearGradient(-5, -50, 5, -50);
 trunkGradient.addColorStop(0, '#663300');
 trunkGradient.addColorStop(0.4, '#996600');
 trunkGradient.addColorStop(1, '#552200');
 context.fillStyle = trunkGradient;
 context.fillRect(-5, -50, 10, 50);

 var canopyShadow = context.createLinearGradient(0, -50, 0, 0);
 canopyShadow.addColorStop(0, 'rgba(0, 0, 0, 0.5)');
 canopyShadow.addColorStop(0.2, 'rgba(0, 0, 0, 0.0)');
 context.fillStyle = canopyShadow;
 context.fillRect(-5, -50, 10, 50);

 createCanopyPath(context);

 context.lineWidth = 4;
 context.lineJoin = 'round';
 context.strokeStyle = '#663300';
 context.stroke();

 context.fillStyle = '#339900';
 context.fill();
 }

 function drawTrails() {
 var canvas = document.getElementById('trails');
 var context = canvas.getContext('2d');
 // 在 X=130, Y=250的位置绘制第一棵树
 context.save();
 context.translate(130, 250);
 drawTree(context);
 context.restore();
 // 在 X=260, Y=500 位置绘制第二棵树
 context.save();
 context.translate(260, 500);

 // 将第二棵树的宽高分别放大至原来的2倍
 context.scale(2, 2);
 drawTree(context);
 context.restore();

 context.save();
 context.translate(-10, 350);
 context.beginPath();
 context.moveTo(0, 0);
 context.quadraticCurveTo(170, -50, 260, -190);
 context.quadraticCurveTo(310, -250, 410,-250);
 context.strokeStyle = context.createPattern(gravel, 'repeat');
 context.lineWidth = 20;
 context.stroke();
 context.restore();
 }
 </script>
</html>


二. 旋转 context.rotate(angle), 参数angle 以弧度为单位

看代码

<!DOCTYPE html>
<html>
<meta charset="UTF-8">
 <title>旋转示例</title>
 <canvas id="trails" style="border: 1px solid;" width="400" height="600"> </canvas>
 <script>
 var gravel = new Image();
 gravel.src = "gravel.jpg";
 gravel.onload = function () {
 drawTrails();
 }

 function createCanopyPath(context) {
 context.beginPath();
 context.moveTo(-25, -50);
 context.lineTo(-10, -80);
 context.lineTo(-20, -80);
 context.lineTo(-5, -110);
 context.lineTo(-15, -110);

 context.lineTo(0, -140);

 context.lineTo(15, -110);
 context.lineTo(5, -110);
 context.lineTo(20, -80);
 context.lineTo(10, -80);
 context.lineTo(25, -50);
 context.closePath();
 }

 // 将绘制树的方法 放到 drawTree()
 function drawTree(context) {
 var trunkGradient = context.createLinearGradient(-5, -50, 5, -50);
 trunkGradient.addColorStop(0, '#663300');
 trunkGradient.addColorStop(0.4, '#996600');
 trunkGradient.addColorStop(1, '#552200');
 context.fillStyle = trunkGradient;
 context.fillRect(-5, -50, 10, 50);

 var canopyShadow = context.createLinearGradient(0, -50, 0, 0);
 canopyShadow.addColorStop(0, 'rgba(0, 0, 0, 0.5)');
 canopyShadow.addColorStop(0.2, 'rgba(0, 0, 0, 0.0)');
 context.fillStyle = canopyShadow;
 context.fillRect(-5, -50, 10, 50);

 createCanopyPath(context);

 context.lineWidth = 4;
 context.lineJoin = 'round';
 context.strokeStyle = '#663300';
 context.stroke();

 context.fillStyle = '#339900';
 context.fill();
 }

 function drawTrails() {
 var canvas = document.getElementById('trails');
 var context = canvas.getContext('2d');
 // 在 X=130, Y=250的位置绘制第一棵树
 context.save();
 context.translate(100, 150);
 context.rotate(1.57); //旋转角度以弧度为单位
 drawTree(context);
 context.restore();

 context.save();
 context.translate(-10, 450);
 context.beginPath();
 context.moveTo(0, 0);
 context.quadraticCurveTo(170, -50, 260, -190);
 context.quadraticCurveTo(310, -250, 410,-250);
 context.strokeStyle = context.createPattern(gravel, 'repeat');
 context.lineWidth = 20;
 context.stroke();
 context.restore();
 }

 </script>
</html>

以上两个示例,需要注意之处:

始终在原点执行图形和路径的变换操作
示例中演示了为什么要在原点执行图形和路径的变换 操作, 执行完后再统一平移. 因为缩放 scale 和旋转 rotate 等变换操作都是针对原点进行的.

如果对一个不在原点的图形进行旋转, 那么图形绕着原点旋转而不是在原地旋转。 类似地,如果进行缩放操作时没有将图形放置到合适的坐标上,那么所有坐标都会被同时缩放, 新的坐标可能会超出canvas 范围。

三. 创建阴影

以下示例,演示如何对路径坐标进行随意变换, 以从根本上改变现在树的路径显示,最终创建一个阴影效果。 相关代码:

<!DOCTYPE html>
<html>
<meta charset="UTF-8">
 <title>变换阴影</title>
 <canvas id="trails" style="border: 1px solid;" width="400" height="600"> </canvas>
 <script>
 var gravel = new Image();
 gravel.src = "gravel.jpg";
 gravel.onload = function () {
 drawTrails();
 }

 function createCanopyPath(context) {
 context.beginPath();
 context.moveTo(-25, -50);
 context.lineTo(-10, -80);
 context.lineTo(-20, -80);
 context.lineTo(-5, -110);
 context.lineTo(-15, -110);

 context.lineTo(0, -140);
 context.lineTo(15, -110);
 context.lineTo(5, -110);
 context.lineTo(20, -80);
 context.lineTo(10, -80);
 context.lineTo(25, -50);
 context.closePath();
 }

 function drawTree(context) {
 context.save();
 // X值随着Y值的增加而增加,借助拉伸变换,可以创建一棵用作阴影的倾斜的树,应用了
 // 变换以后,所有坐标都与矩阵相乘
 context.transform(1, 0, -0.5, 1, 0, 0);

 // 在Y轴方向,将阴影的高度压缩为原来的60%
 context.scale(1, 0.6);

 // 使用透明度为20%的黑色填充树干
 context.fillStyle = 'rgba(0, 0, 0, 0.2)';
 context.fillRect(-5, -50, 10, 50);

 // 使用已有的阴影效果重新绘制
 createCanopyPath(context);
 context.fill();
 context.restore();

 var trunkGradient = context.createLinearGradient(-5, -50, 5, -50);
 trunkGradient.addColorStop(0, '#663300');
 trunkGradient.addColorStop(0.4, '#996600');
 trunkGradient.addColorStop(1, '#552200');
 context.fillStyle = trunkGradient;
 context.fillRect(-5, -50, 10, 50);

 var canopyShadow = context.createLinearGradient(0, -50, 0, 0);
 canopyShadow.addColorStop(0, 'rgba(0, 0, 0, 0.5)');
 canopyShadow.addColorStop(0.2, 'rgba(0, 0, 0, 0.0)');
 context.fillStyle = canopyShadow;
 context.fillRect(-5, -50, 10, 50);

 createCanopyPath(context);

 context.lineWidth = 4;
 context.lineJoin = 'round';
 context.strokeStyle = '#663300';
 context.stroke();

 context.fillStyle = '#339900';
 context.fill();
 }
 function drawTrails() {
 var canvas = document.getElementById('trails');
 var context = canvas.getContext('2d');
 context.save();
 context.translate(130, 250);
 drawTree(context);
 context.restore();

 context.save();
 context.translate(260, 500);
 context.scale(2, 2);
 drawTree(context);
 context.restore();

 context.save();
 context.translate(-10, 350);
 context.beginPath();
 context.moveTo(0, 0);
 context.quadraticCurveTo(170, -50, 260, -190);
 context.quadraticCurveTo(310, -250, 410,-250);
 context.strokeStyle = context.createPattern(gravel, 'repeat');
 context.lineWidth = 20;
 context.stroke();
 context.restore();
 }
 </script>
</html>

分析这种变换背后的数学含义, 可以看出通过调整与Y轴值相对应的参数改变了X轴的值, 这样做是为了拉伸出一查灰色的树做阴影。 接下来, 我们按照60% 的比例将剪裁出的树缩小到了合适的尺寸。

剪裁过的 “阴影” 树会先被显示出来, 这样一来, 真正的树就会按照Z轴(canvas 中对象的重叠顺序) 显示在阴影的上面。 此外树影的填充用到了CSS 的RGBA特性, 通过特性我们将透明度值设为正常情况下的20%, 至此,带有半透明效果的树影就做好了。

示例中用到图片 gravel.jpg 在之前博文可找到.

下载本文
显示全文
专题