zl程序教程

您现在的位置是:首页 >  前端

当前栏目

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

html5开发 详解 简单 变换 Canvas 2.7 画布
2023-09-11 14:17:44 时间

本节书摘来自异步社区《HTML5 canvas开发详解(第2版)》一书中的第2章,第2.7节,作者: 【美】Steve Fulton , Jeff Fulton 更多章节内容可以访问云栖社区“异步社区”公众号查看。

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 

 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 

 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 

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

 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 

 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 

 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 

 img src="https://yqfile.alicdn.com/3d4a801af305ab8494d925b7fff86064e542c844.png " 

 /div 

**2.7.3 缩放和旋转组合变换**

如果对对象进行缩放和旋转操作,Canvas变换可以轻松地组合并生成想要的效果,如图2-20所示。例2-12显示了如何在前面的示例中使用scale(2,2)和rotate(angleInRadians)进行组合变换。

 div 

 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"
 a href=https://yqfile.alicdn.com/1a5bd984c61b59c2625345f660a0dd7c17df0f8a.png"

找到任何形状的中心

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

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


c26c797c9f188ea79ed13370fa5eeaeaedd42700

SpringBoot框架+原生HTML开发的云电子病历系统源码 SaaS模式Java版云HIS系统的子系统云电子病历系统源码,本系统采用前后端分离模式开发和部署,支持电子病历四级。智能化模板、全结构化录入,支持全结构化选择、模板输入、表格式、文本等多种录入方式。
IOT智慧物联网平台源码 后台基于JAVA开发 前端HTML 目前web系统功能已实现: 1、 数据实时采集和远程控制; 2、 报警信息管理和报表导出; 3、 自动控制,触发管理; 4、 历史数据,报表导出功能; 5、 子账户和场景授权管理; 6、 场景信息管理;
基于.Net开发的对比Html效果差异的开源项目 基于.Net 4.5开发的对比Html文件、片段效果差异的项目。两份Html效果不一样的地方会通过颜色、删除线、背景色分别标记出来。
传统html+vue+elementUI开发&nodeJS环境搭建 Shiro提供了完整的企业级会话管理功能,不依赖于底层容器(如Tomcat、WebLogic),不管是J2SE还是J2EE环境都可以使用,提供了会话管理,会话事件监听,会话存储/持久化,容器无关的集群,失效/过期支持,对Web的透明支持,SSO单点登录的支持等特性。 所谓会话,即用户访问应用时保持的连接关系,在多次交互中应用能够识别出当前访问的用户是谁,且可以在多次交互中保存一些数据。如访问一些网站时登录成功后,网站可以记住用户,且在退出之前都可以识别当前用户是谁。
异步社区 异步社区(www.epubit.com)是人民邮电出版社旗下IT专业图书旗舰社区,也是国内领先的IT专业图书社区,致力于优质学习内容的出版和分享,实现了纸书电子书的同步上架,于2015年8月上线运营。公众号【异步图书】,每日赠送异步新书。