canvas-drawImage()⽅法绘制图⽚不显⽰的问题canvas有个很强⼤的api是drawImage()():
他的主要功能就是绘制图⽚、视频,甚⾄其他画布等。
问题:
慕名赶来,却⼀脚踩空,低头⼀看,地上⼀个⼤坑。
事情是这样的,在我看完w3c的介绍和很有说服⼒和教学⼒的demo后,本着实践出真知的思想决定上⼿⼀试,这⼀试不要紧~
我按照流⽔线⼯程铺设以下⼏点基本⼯作:
1. canvas标签+id
<canvas id="canvas1"></canvas>
2. 获取canvas+设置宽⾼
var cav1 = ElementById('canvas1'),
wWidth = 800,
wHeight = 600;
cav1.width = wWidth;
cav1.height = wHeight;
3. getContext('2d')准备画布
var ctx1 = Context('2d');
4. new⼀个Image()对象,并付给他我喜欢...的图⽚(别想多了)的属性
var bgImg = new Image();
bgImg.src = 'images/background.jpg';
5. 终于到了绘图。兴冲冲的写下这段代码:
ctx1.drawImage(bgImg,0,0,wWidth,wHeight);
流着哈喇⼦,我在浏览器按下了F5。
然后⼀⽚死寂...
以为代码写错了,再回去仔细检查⼀遍,没错啊。
复制w3c的关键属性名及⽅法再检查⼀遍,确实没错啊。
图⽚打印出来,也有这个(⼈)图啊!
后来观察w3c的案例,和我代码的区别就是他的图⽚是在html⾥边的。
然后我就学着向html⾥边插⼊了图⽚,
<img src="./images/background.jpg" id="imgs" ></img>
并且⽤getElementById获取这个元素,
var bgImg = ElementById('imgs')
再次执⾏绘图竟然可以了。
他竟然可以了!
难过的想,就必须要实体吗?不就是放到了canvas标签前边嘛!js加载也有实体啊,⽽且我还是⽤new的啊,⽐真⼈差哪了!
对啊,不就是放到前边了嘛。这就涉及到⼀个顺序问题啊!
电脑壁纸图片js⾥加载的图⽚是放在绘图前边没错,但是图⽚加载进来还需要个时间啊。需要给图⽚缓冲的时间。
等图⽚加载成功后才可以进⾏绘制。
⽽drawImage这个⽅法,当图⽚在没加载完的情况下使⽤,他会不被调⽤。绘制就会失败。
原来如此!
就有⼈抬杠说img标签⾥的图⽚不需要时间加载吗?这时候drawImage就不受限制了?!
但是你不要忽略了,js开头的  load  的啊,就算图⽚加载再慢,就算图⽚标签的顺序在canvas标签的后边,但是我有load罩着,我图⽚加载不完,你drawImage就没戏啊对不对。
⼤概顺序是这样的:
<img src="">
关于书的名人名言
  drawImage
}
如果不是在html结构中插⼊的图⽚,就被我的粗⼼绕过了这个限制:
图⽚作为⼀个资源请求,在js中加载时,⾃然也会有⼀个图⽚加载的时间。
但是因为没有限制,极⼤的情况是当图⽚还没有加载完毕就调⽤了drawImage,此⽅法他是不起作⽤的。
解决:
那有没有好的⽅法解决因图⽚加载顺序导致drawImage绘图失败的情况呢?
我总结了以下三种⽅法:
1. 标签+load
皱组词语
<img src="">
  context.drawImage()
}
这种做法解决的核⼼是onload,将图⽚和drawImage分开加载,img先加载,确保加载完毕以后再使⽤绘图
1-2. 后期插⼊标签?是否可⾏
有⼀种情况是,使⽤截图功能时,也可以⽤drawImage,⽽截图⼜不不是截⾃⼰既有的图⽚,⽽是⽤⼀个图⽚的地址当参数.
我想这种的就需要js来创建⼀个img,并将地址赋给它.然后⽣成图⽚再来截图了
var myImg = ateElement('img');
myImg.src = '///';
我为什么要当教师
document.body.appendChild(myImg);
ctx1.drawImage(myImg,0,0,wWidth,wHeight);
不想加多余的标签?必要像下边这样⽤js来new⼀个image对象?
var bgImg = new Image();
bgImg.src = 'images/background.jpg';
前边说了,这种使⽤  new Image()  创建的图⽚,需要给图⽚缓冲的时间。等图⽚加载成功后才可以进⾏绘制。
图⽚对象是准备好了,但你怎么知道图⽚什么时候真的加载完成呢?
好,还有办法:
js任务执⾏中,你嫌我离你执⾏的时间太近是不,那把我单独拎出来重新排队,等会再执⾏可以否?()
2. 定时器异步实现
setTimeout(function(){
ctx1.drawImage(bgImg,0,0,wWidth,wHeight);
},10)
这⾥为什么延迟写了10,没写⼤家熟悉的1000或者0呢?
因为在我的特定wifi环境特定台式机电脑的测试下,10能在图⽚加载完后刚好图⽚出来,⽽不像0那样不出来,也不想1000那样等半天出来。
可是试想⼀下,换⼀个更⼤的图,这个10还适⽤吗?wifi换成2g这个10还适⽤吗?
所以,定时器的缺点就是,不能保证时间到了以后图⽚已经加载进来了,⽹不快的话照样挂掉。
3. load
使⽤img的加载事件,监听图⽚加载成功后,再执⾏canvas的绘图效果.并且这种⽅法靠谱⼀些。
load = function(){
2    console.log('图⽚加载成功');
3    console.log(this);
4    ctx1.drawImage(bgImg,0,0,wWidth,wHeight);
纂书5 }
其实这三种⽅法都是⼀个核⼼,就是让图⽚先加载。即图⽚预加载。
但是对于缓存图⽚,图⽚预加载还需要解决的是,当页⾯不刷新时监听缓存图⽚的问题,这个问题。
⼜发现⼀个问题。。。。
⾸先,背景图画完的样⼦长这样。
然后好不容易背景图画出来了,我就开开⼼⼼的继续吧。
于是我紧接着画了⼀条红线,为了避免看不到,我还把宽度增加到了20:
ctx1.drawImage(bgImg,0,0,wWidth,wHeight);
}
/* 绘制红线如下: */
ctx1.beginPath();
ctx1.lineTo(10,wHeight-100);
ctx1.lineWidth = 20;
ctx1.strokeStyle = 'red';
ctx1.stroke();
ctx1.closePath();
有机硅材料
但我F5按下依旧没有变化,还是看不到红线。
了半天直到我把背景图关掉才看到:
啊,原来他被背景图盖住啦!
可是,为什么呢?
我在想有两种可能
1、层级问题
2、先后问题
关于1,就像css的z-index那种感觉,是背景图在上盖住了红线。难道说背景图的层级⽐红线⾼?
这个设想我没法测试,于是放弃进⾏第⼆种可能的揭秘。
可是为什么背景图会在上呢?是因为背景图后画?
这个可以最简便的通过console.log()打印观察执⾏顺序
原来“罪魁祸⾸”竟然是onload这个回调。他跟定时器⼀样,都是⼀个异步任务。⾃然排在了同步任务(下边的绘制线条)的后边所以前边看似是⼀个很好的解决⽅法——onload,在这⾥也暴露了他的弊端。
很好、看来,promise学习⼤计宜趁早提上⽇程啊!哈哈哈
2018-09-28  12:38:03