《HTML5 canvas开发详解(第2版)》——2.7 简单画布变换

2.7 简单画布变换

画布变换是指用数学方法调整所绘形状的物理属性。缩放和旋转是常用的两个形状变换,本节将做专门讨论。

所有变换都依赖于后台的数学矩阵运算。幸运的是,读者只需使用变换功能而不必去理解这些运算。接下来,本书将讨论如何通过调整Canvas属性来应用旋转和缩放变换。

2.7.1 旋转和平移变换
首先指定画布上的对象面向左侧时处于角度为0的旋转状态(如果对象有“面”,则很重要;如果对象没有“面”,也可将其作为参照)。例如,画一个方框(四边等长),它并没有一个与其他边相比而言初始就朝向左侧的“面”。现在,将其画出来作为参考。

//绘制一个红色正方形
context.fillStyle = "red";
context.fillRect(100,100,50,50);
如```
果将画布旋转45°,那么需要进行以下操作。将Canvas变换设置为identity(或“reset”)矩阵。

context.setTransform(1,0,0,1,0,0);

由于Canvas使用的是弧度,而不是角度,在设定变换时应将45°角转换成弧度。

var angleInRadians = 45 * Math.PI / 180;
context.rotate(angleInRadians);

1.在调用setTransform()或其他变换函数后,将变换应用到形状和路径上
如果照抄这段代码运行,将发生很有趣的运行结果:屏幕上什么也没有!这是因为只有对画布应用setTransform()函数后才对形状起作用。示例中先绘制了一个正方形,然后设置变换属性。这将不会对这个使正方形发生改变(或者变换)。例2-7给出了能产生预想结果的正确代码顺序,结果如图2-12所示。

例2-7 简单旋转变换

function drawScreen(){

   //绘制一个红色正方形
   context.setTransform(1,0,0,1,0,0);
   var angleInRadians = 45 * Math.PI / 180;
   context.rotate(angleInRadians);
   context.fillStyle = "red";
   context.fillRect(100,100,50,50);
  }

<div style="text-align: center">
 <img src=" https://yqfile.alicdn.com/78e1e918028c93833a7351a079509ea195848639.png" >
</div>

虽然得到了变换结果,但是估计和读者想要的结果会有所不同。虽然红色的方框旋转了,但是好像画布也跟着一起旋转了。实际上,画布并没有旋转,context.rotate()函数调用后只有部分被绘制出来。那么,为什么这个正方形旋转到了屏幕外?因为旋转原点设在了“nontranslated”(0,0)点,所以导致了正方形从整个画布的左上角旋转。

例2-8提供了一个略微不同的场景:先画一个黑色方块,然后设置旋转变换,最后再画这个红色方块。结果如图2-13所示。

例2-8 旋转以及Canvas状态

function drawScreen(){

   //绘制黑色正方形
   context.fillStyle = "black";
   context.fillRect(20,20,25,25);

   //绘制红色正方形
   context.setTransform(1,0,0,1,0,0);
   var angleInRadians = 45 * Math.PI / 180;
   context.rotate(angleInRadians);
   context.fillStyle = "red";
   context.fillRect(100,100,50,50);
  }

<div style="text-align: center">
 <img src=" https://yqfile.alicdn.com/9ed59505ffddf84921be0e4a22ca74c8fd729b8c.png" >
</div>
这个黑色小方块没受到旋转的影响,因为只有调用context.rotate()函数之后绘制的形状才会受到影响。

同样,红方块移到了左侧之外。重申一下,这是因为画布不知道旋转的原点在哪里而造成的。如果没有平移到实际的原点,Canvas就会认为就在点(0,0),结果导致context.rotate()函数围绕点(0,0)旋转。这将会使读者领会到下面的内容。

2.只有将原点平移至形状中心,对象才会围着自己转
将例2-8加以改变,使红色正方形能在旋转45°的同时保持位置不变。

首先,设置好控制红色正方形属性的fillRect()函数的变量。虽然不必这样做,但是这会使代码更易于阅读和调整。

var x = 100;
var y = 100;
var width = 50;
var height = 50;

接下来,使用context.translate()函数,将画布原点平移到红色正方形的中心点。这个函数可以将画布原点移到(x,y)处。这里将原点x坐标值设为红色正方形左上角的x值(100)加上其一半的宽度。使用前面创建的变量即可控制这个红色正方形的属性,如下所示:

x+0.5*width

接下来,确定原点平移的y坐标值。这次使用左上角的y值和形状的高度值,如下:

y+.05*height

translate()函数语句如下:

context.translate(x+.05width, y+.05height)

既然画布已经平移到了正确的原点,下面就可以进行旋转变换了,代码不变。

context.rotate(angleInRadians);

最后,绘制出形状。由于画布原点已经移动到将要绘制形状的位置,因此不能简单重复使用例2-8中同样的数值。现在,将(125,125)作为一切绘制操作的原点。125是将正方形左上角的x值(100)加上其一半宽度(25)得来的。y值同上。translate()方法调用完成。

绘制对象需要从正确的左上角坐标值(x,y)开始,进而从原点的x值减去宽的一半,从y值减去高的一半。

context.fillRect(-0.5width,-0.5height, width, height);

为什么要这样做?如图2-14所示。

<div style="text-align: center">
 <img src="https://yqfile.alicdn.com/2cfc6e21cb13bb30629aa85b7a4f66f84746870a.png " >
</div>

试想一下,从左上角开始绘制正方形,如果原点在(125,125),左上角实际上是(100,100)。然而原点已经平移过了,也就是说,(125,125)现在相当于(0,0)。如果在未平移的画布上画这个方块,则应从(−25,−25)点开始。

因此,必须把绘制正方形当成从(0,0)开始,而不是从(125,125)开始。实际绘图的时候,必须使用图2-15所示的坐标。

<div style="text-align: center">
 <img src=" https://yqfile.alicdn.com/45ad2bda47e71a79752d2b6a127f307da19a19b5.png" >
</div>

小结:变换需要将原点平移到正方形的中心,以使其围绕自己旋转。绘图的时候,需要使代码将(125,125)当作实际的(0,0)点。如果不平移原点,那么也可以使用(125,125)作为正方形的中心,如图2-14所示。例2-9说明了代码如何运行,结果如图2-16所示。

例2-9 围绕中心点旋转

function drawScreen(){

   //绘制黑色正方形
   context.fillStyle = "black";
   context.fillRect(20,20 ,25,25);

   //绘制红色正方形
   context.setTransform(1,0,0,1,0,0);
   var angleInRadians = 45 * Math.PI / 180;
   var x = 100;
   var y = 100;
   var width = 50;
   var height = 50;
   context.translate(x+.5width, y+.5height);
   context.rotate(angleInRadians);
   context.fillStyle = "red";
   context.fillRect(-.5width,-.5height , width, height);
  }

<div style="text-align: center">
 <img src=" https://yqfile.alicdn.com/d71354fcaee4d4ac561d743995e9b876fd69825a.png" >
</div>

再看一个旋转的例子。例2-10在例2-9的基础上增加了4个单独的40×40的正方形,每个稍加旋转,结果如图2-17所示。

例2-10 旋转多个正方形

function drawScreen(){

   //绘制一个红色正方形
   context.setTransform(1,0,0,1,0,0);
   var angleInRadians = 45 * Math.PI / 180;
   var x = 50;
   var y = 100;
   var width = 40;
   var height = 40;
   context.translate(x+.5width, y+.5height);
   context.rotate(angleInRadians);
   context.fillStyle = "red";
   context.fillRect(-.5width,-.5height , width, height);

   context.setTransform(1,0,0,1,0,0);
   var angleInRadians = 75 * Math.PI / 180;
   var x = 100;
   var y = 100;
   var width = 40;
   var height = 40;
   context.translate(x+.5width, y+.5height);
   context.rotate(angleInRadians);
   context.fillStyle = "red";
   context.fillRect(-.5width,-.5height , width, height);

   context.setTransform(1,0,0,1,0,0);
   var angleInRadians = 90 * Math.PI / 180;
   var x = 150;
   var y = 100;
   var width = 40;
   var height = 40;
   context.translate(x+.5width, y+.5height);
   context.rotate(angleInRadians);
   context.fillStyle = "red";
   context.fillRect(-.5width,-.5height , width, height);
   context.setTransform(1,0,0,1,0,0);
   var angleInRadians = 120 * Math.PI / 180;
   var x = 200;
   var y = 100;
   var width = 40;
   var height = 40;
   context.translate(x+.5width, y+.5height);
   context.rotate(angleInRadians);
   context.fillStyle = "red";
   context.fillRect(-.5width,-.5height , width, height);
}

<div style="text-align: center">
 <img src="https://yqfile.alicdn.com/78c657ae3ca0af6c81ba95d30e22d977efacb120.png " >
</div>

**2.7.2 缩放变换**
context.scale()函数有两个参数:第一个是x轴的缩放属性,第二个是y轴的缩放属性。一个对象的正常缩放大小数值是1。因此,如果要将一个对象放大两倍,就可以将两个参数都设为2。在drawScreen()中使用下面这段代码可以产生一个红色正方形,如图2-18所示。

context.setTransform(1,0,0,1,0,0);
context.scale(2,2);
context.fillStyle = "red";
context.fillRect(100,100 ,50,50);

<div style="text-align: center">
 <img src=" https://yqfile.alicdn.com/c6c40d207655d01dc341d6aefda2afd819b38d87.png" >
</div>

如果测试这段代码,就会发现缩放的工作方式与旋转差不多。由于没有平移原点来对正方形进行缩放,而仍用画布左上角作为画布原点,因此红色的正方形向右下方移动了。如果从正方形的中心缩放,就需要在缩放之前将原点平移到正方形中心,然后再围绕这个中心点绘图(见例2-9)。例2-11的结果如图2-19所示。

例2-11 从中心点缩放

function drawScreen(){

   //绘制一个红色正方形
   context.setTransform(1,0,0,1,0,0);
   var x = 100;
   var y = 100;
   var width = 50;
   var height = 50;
   context.translate(x+.5width, y+.5height);
   context.scale(2,2);
   context.fillStyle = "red";
   context.fillRect(-.5width,-.5height , width, height);
  }

<div style="text-align: center">
 <img src="https://yqfile.alicdn.com/3d4a801af305ab8494d925b7fff86064e542c844.png " >
</div>
**2.7.3 缩放和旋转组合变换**
如果对对象进行缩放和旋转操作,Canvas变换可以轻松地组合并生成想要的效果,如图2-20所示。例2-12显示了如何在前面的示例中使用scale(2,2)和rotate(angleInRadians)进行组合变换。

<div style="text-align: center">
 <img src=" https://yqfile.alicdn.com/f63a8748697e67dcb8ee1231111ea4457aff31f3.png" >
</div>

例2-12 缩放和旋转组合

function drawScreen(){
   context.setTransform(1,0,0,1,0,0);
   var angleInRadians = 45 * Math.PI / 180;
   var x = 100;
   var y = 100;
   var width = 50;
   var height = 50;
   context.translate(x+.5width, y+.5height);
   context.scale(2,2);
   context.rotate(angleInRadians);
   context.fillStyle = "red";
   context.fillRect(-.5width,-.5height , width, height);
  }

例2-13也组合了旋转和缩放,这个例子是对矩形进行操作,如图2-21所示。

例2-13 非正方形对象的缩放和旋转

function drawScreen(){

   //绘制一个红色矩形
   context.setTransform(1,0,0,1,0,0);
   var angleInRadians = 90 * Math.PI / 180;
   var x = 100;
   var y = 100;
   var width = 100;
   var height = 50;
   context.translate(x+.5width, y+.5height);
   context.rotate(angleInRadians);
   context.scale(2,2);

   context.fillStyle = "red";
   context.fillRect(-.5width,-.5height , width, height);
  }

s`
tyle="text-align: center">
https://yqfile.alicdn.com/1a5bd984c61b59c2625345f660a0dd7c17df0f8a.png" >

找到任何形状的中心

对矩形或其他形状进行旋转和缩放与对正方形非常类似,实际上只要在缩放、旋转或者组合缩放旋转前将原点平移到形状的中心,都可以得到想要的效果。记住,任何形状的中心点都是半宽的x值和半高的y值!这需要使用边界框理论找到中心点。

图2-22说明了这个理论,尽管不是简单形状,也可以找到包含对象任一点的边界框。图2-22接近正方形,但是同样符合矩形的边界框理论。

时间: 2024-08-02 07:30:19

《HTML5 canvas开发详解(第2版)》——2.7 简单画布变换的相关文章

《HTML5 canvas开发详解(第2版)》——导读

前言第2版介绍自从本书第1版发行之后,在过去的两年里,HTML5 Canvas的使用有了突飞猛进的增长.本书的第1版可以称得上是第一批介绍Canvas的专著之一.在我们为自己的快速而感到自豪同时也意味着我们曾经独自进行了大量的研究和探索.早在2011年,只有极少数HTML5 Canvas应用的例子和教程.但在2013年情形发生了改变.现在有许多关于HTML5 Canvas的资源可供选择,从框架到API,有许多网站和书籍进行专门的阐述.为了编写第2版,我们进行了大量艰辛的工作来检查在第1版中哪些部

《HTML5 Canvas开发详解》——导读

https://yqfile.alicdn.com/bc81e95aba389209ecb7176965c56b0ba2d9c780.png" > 前言HTML5 Canvas为开发者提供了一个新的机会,利用它仅使用普通的HTML和JavaScript语言就可以在常见的浏览器中创建动画图形.Canvas是HTML5中使用率最高的一部分,它被用于许多演示与游戏.它提供了视觉效果很棒的交互特性,而且它还提供了非常大的自由度,几乎允许开发者在浏览器窗口中做任何事情.然而它与JavaScript的

《HTML5 Canvas开发详解》——2.7 简单画布变换

2.7 简单画布变换 画布变换是指用数学方法调整所绘形状的物理属性.缩放和旋转是常用的两个形状变换,本节将专门讨论. 所有变换都依赖于后台数学矩阵运算.幸运的是,读者只需使用变换功能而不必去理解这些运算.接下来,本书将讨论如何通过调整Canvas属性来应用旋转和缩放变换. 2.7.1 旋转和平移变换首先指定画布上的对象面向左侧时处于角度为0的旋转状态(如果对象有"面",这很重要,如果对象没有"面",也可将其作为参照).例如画一个方框(四边等长),它并没有一个与其他边

《HTML5 Canvas开发详解》——2.3 Canvas状态

2.3 Canvas状态 在Canvas上下文中绘图时可以利用所谓的绘图堆栈状态.每个状态随时存储Canvas上下文数据.下面是存储在状态堆栈的数据列表. 变换矩阵信息,例如旋转或平移时使用context.rotate()方法和context.setTransform()方法. 当前剪贴区域. 画布属性的当前值,如下所示(但不限于). -globalAlpha -globalCompositeOperation -strokeStyle -textAlign, textBaseline -lin

《HTML5 canvas开发详解(第2版)》——1.6 HTML5 Canvas版“Hello World!”

1.6 HTML5 Canvas版"Hello World!" 如前所述,将Canvas放入HTML5页面时第一件要做的事就是,看看整个页面是否已经加载,并且开始操作前是否所有HTML元素都已展现.在用Canvas处理图像和声音的时候,这点会非常重要. 为此,这里要使用JavaScript的事件.当定义的事件发生时,事件从对象发出.其他对象监听事件,这样就可以基于事件进行处理.用JavaScript可以监听对象的一些常见事件,包括键盘输入.鼠标移动以及加载结束. 第一个需要监听的事件是

《HTML5 canvas开发详解(第2版)》——第1章 HTML5 Canvas简介1.1 什么是HTML5

第1章 HTML5 Canvas简介 HTML5是新一代的HTML,即超文本标记语言.HTML从1993年第一次标准化后,便奠定了万维网的基础.HTML通过使用将标签用尖括号(< >)括起来的方式定义Web页面内容. HTML5 Canvas是屏幕上的一个由JavaScript控制的即时模式位图区域.即时模式是指在画布上呈现像素的方式,HTML Canvas通过JavaScript调用Canvas API,在每一帧中完全重绘屏幕上的位图.作为一名程序员,所要做的就是在每一帧渲染之前设置屏幕的显

《HTML5 Canvas开发详解》——1.5 HTML5 Canvas版“Hello World!”

1.5 HTML5 Canvas版"Hello World!" 如前所述,将Canvas放入HTML5页面时第一件要做的事,就是看看整个页面是否已经加载,并且开始操作前是否所有HTML元素都已展现.用Canvas处理图像和声音的时候这点会非常重要. 为此,这里要使用JavaScript的事件.当定义的事件发生时,事件从对象发出.其他对象监听事件,这样就可以基于事件进行处理.用JavaScript可以监听对象的一些常见事件,包括键盘输入.鼠标移动以及加载结束. 第一个需要监听的事件是wi

《HTML5 canvas开发详解(第2版)》——1.11 动画版本的Hello World

1.11 动画版本的Hello World "Hello World"和"猜字母"本身都是不错的示例,但是它们都没能回答出"为什么"--究竟为什么要使用HTML5 Canvas?自创立以来,静态的图像和文字就是HTML的领域,那么画布的不同之处在哪里呢?要回答这个问题,需要创建第二个"Hello World"示例.这个示例将介绍画布与HTML上的其他显示方式的最大不同之处:动画.在这个示例中,将为"Hello Wor

《HTML5 canvas开发详解(第2版)》——1.9 HTML5 Canvas对象

1.9 HTML5 Canvas对象 Canvas对象是通过在HTML页面的< body >部分中放置< canvas >标签创建的,也可以通过以下代码创建画布实例. var theCanvas = document.createElement("canvas"); Canvas对象有两个相关的属性和方法可以通过JavaScript访问:width和height.这些属性显示当前HTML页面创建的画布的宽度和高度.这里需要强调的是,这两个属性并不是只读的.例如,