问题出处
在初学html的canvas时,我们遇到了对图形的移动,放大,旋转的操作;会发现在使用translate();scale()和rotate()的时候,都只是再次绘画了一个图形,接下来我们以边框为例子,进行演示。
我们先建立骨架,和绘制一个边框
<body onload="drawrect()"> //预先加载绘制边框函数
<div>
<button onclick="moveX_rect(1)">上移</button><button onclick="moveX_rect(0)">下移</button>
</div>
<canvas id="mycanvas" width="1700px" height="800px" style="background-color:gray; border:3px black solid;"
onmousemove="getcnvsxy(event)" onmouseout="cleanxy()"></canvas>
<script>
function getbyid(id){ //定义通过id获取元素的函数
return document.getElementById(id);
}
function drawrect(){ //绘制边框函数
var cnv=getbyid("mycanvas");
var cxt=cnv.getContext("2d");
cxt.lineWidth=5; //边框线的宽度为5
cxt.strokeStyle="black"; //边框线的颜色为黑
cxt.strokeRect(200,100,100,100); //从X为200px,Y为100px的位置绘制一个长100px宽100px的边框
}
function moveX_rect(a){ //定义移动函数
var cnv=getbyid("mycanvas");
var cxt=cnv.getContext("2d");
a?cxt.translate(0,-10):cxt.translate(0,10); //onlick触发的是参数不同的同一个函数,用三目运算来决定是上移还是下移
drawrect(); //调用绘制函数,再绘制一个移动后的函数
}
</script>
</body>
在以上代码执行后效果图:
我们接下来进行三次上移观察效果:
四次下移后:
我们会发现,每次上移,都会保留原先的边框,原因就是我们在移动的图形时,使用了drawrect()重新绘制了一个新边框,只不过是位置变了而已!那我们如何解决呢???
在课本《移动WEB开发实战》的一串代码中我得到了启发:
function spn1_click(){
var cnv=$$("cnvMain");
var cxt=cnv.getContext("2d");
cxt.translate(-20,-20);
drawRect();
cxt.translate(40,40);
drawRect();
}
这串代码的意思是想让我们发现,每次移动都是相对上一次而做出的改变,效果图就不展示了,口头赘述一下:第一次(-20,-20),我们的图形X轴-20,Y轴-20,整个图形往左上角移动;第二次(40,40),我们的图形X轴+40,Y轴+40,第一次移动后的图形,也就是在左上角的图形往右下角移动第一次的两倍距离;我觉得我是时候放张图了:
解决思路与方案!!!
既然一次可以绘制两个图形,咱就让一个图形覆盖住原先的图形!?
在上述书本提到的例子中,有两个drawrect()函数,我们可以把其中一个变成translate(0,0),让它先绘制的图形覆盖住原先的图形,既然要让原先的图形看不见,咱就是说,把先绘制的图形颜色设置成和背景颜色一样,这就看不见啦!!!
例如:在我给出的代码中,我们这样修改:
1.复制一份drawrect(),把名字改为drawrect1()
2.drawrect1()里面我们把颜色设置成和背景颜色一样
3.在moveX_rect(a)函数绘制移动图形之前调用cxt.translate(0,0)和drawrect1()
修改后的JS代码如下:
function drawrect(){
var cnv=getbyid("mycanvas");
var cxt=cnv.getContext("2d");
cxt.strokeStyle="black";
cxt.lineWidth=5;
cxt.strokeRect(200,100,100,100)
}
function drawrect1(){ //这是新定义的绘制和背景颜色一样的边框
var cnv=getbyid("mycanvas");
var cxt=cnv.getContext("2d");
cxt.strokeStyle="gray"; //边框颜色和背景颜色一样
cxt.lineWidth=5;
cxt.strokeRect(200,100,100,100);
}
function moveX_rect(a){
var cnv=getbyid("mycanvas");
var cxt=cnv.getContext("2d");
cxt.translate(0,0);
drawrect1(); //在我们移动前,先绘制边灰色框覆盖住原先的黑色边框
a?cxt.translate(0,-10):cxt.translate(0,10);
drawrect();
}
我们再来看看效果(上移三次,下移四次):
为什么会有黑色细边框呢??
后来我们发现,绘制的灰色边框宽度为5,原始黑色边框也为5,是这个原因导致灰色边框遮不住黑色边框呀!!所以,为了一探究竟,我们把灰色的边框宽度调整几次来看看!
我们把drawrect1()里的 “cxt.lineWith=5”改成“cxt.lineWith=3”:效果如下:
很明显可以看到 ‘linewith=3’ 的灰色边框盖不住‘linewith=5’的黑色边框,才会形成细细的黑色边框
所以我们在drawrect1()中,linewith一定要比原先的图形大,才能完全覆盖的住,也就是我们所看到的的清除了原先的图形
我们把linewith设置成6:就能让黑色边框自由的上下移动啦!!
问题解决:
解决完问题后的代码如下:
<body onload="drawrect()">
<div>
<button onclick="moveX_rect(1)">上移</button><button onclick="moveX_rect(0)">下移</button>
</div>
<canvas id="mycanvas" width="1700px" height="800px" style="background-color:gray; border:3px black solid;"
onmousemove="getcnvsxy(event)" onmouseout="cleanxy()"></canvas>
<script>
function getbyid(id){
return document.getElementById(id);
}
function drawrect(){
var cnv=getbyid("mycanvas");
var cxt=cnv.getContext("2d");
cxt.strokeStyle="black";
cxt.lineWidth=5;
cxt.strokeRect(200,100,100,100)
}
function drawrect1(){
var cnv=getbyid("mycanvas");
var cxt=cnv.getContext("2d");
cxt.strokeStyle="gray";
cxt.lineWidth=6;
cxt.strokeRect(200,100,100,100);
}
function moveX_rect(a){
var cnv=getbyid("mycanvas");
var cxt=cnv.getContext("2d");
cxt.translate(0,0);
drawrect1();
a?cxt.translate(0,-10):cxt.translate(0,10);
drawrect();
}
</script>
</body>
</html>
举一反三:
我们在上下移动可以,在左右移动,旋转和放大缩小也能做到!
注意!!!
在后续的测试中我们发现若在放大和缩中会出现这种情况:
随着放大缩小的次数不断增加,盖不住的情况就会显现,也就是说,黑色细边框又会冒出来:
在放大与缩小中,我们发现,其实是让整个画布进行放大和缩小,所以边框的位置也会进行放大和缩小,在这种情况下,每次放大和缩小都存在着长宽按比例进行运算会出现小数,这种小数会以误差的形式展现出来,随着次数增多,误差就越大,黑色细边框就越明显。
总结
放大和缩小的问题属于个人理解和推测,具体原因大家可以进行深入的研究,在我看来,这种解决方案只适用于新手和初学者理解canvas的机制,对于多种图案移动或大型的项目制作可能不适用,此文章仅供参考!!