详解canvas drawImage()方法绘制图片不显示的问题


Posted in HTML / CSS onOctober 08, 2018

canvas有个很强大的api是drawImage()(w3c):

他的主要功能就是绘制图片、视频,甚至其他画布等。

问题:

慕名赶来,却一脚踩空,低头一看,地上一个大坑。

事情是这样的,在我看完w3c的介绍和很有说服力和教学力的demo后,本着实践出真知的思想决定上手一试,这一试不要紧~

我按照流水线工程铺设以下几点基本工作:

1. canvas标签+id

<canvas id="canvas1"></canvas>

2. 获取canvas+设置宽高

var cav1 = document.getElementById('canvas1'),
      wWidth = 800,
      wHeight = 600;
      cav1.width = wWidth;
      cav1.height = wHeight;

3. getContext('2d')准备画布

var ctx1 = cav1.getContext('2d');

4. new一个Image()对象,并付给他我喜欢...的图片(别想多了)的属性

var bgImg = new Image();
bgImg.src = 'images/background.jpg';

5. 终于到了绘图。兴冲冲的写下这段代码:

ctx1.drawImage(bgImg,0,0,wWidth,wHeight);

流着哈喇子,我在浏览器按下了F5。

然后一片死寂...

以为代码写错了,再回去仔细检查一遍,没错啊。

复制w3c的关键属性名及方法再检查一遍,确实没错啊。

图片打印出来,也有这个(人)图啊!

详解canvas drawImage()方法绘制图片不显示的问题

详解canvas drawImage()方法绘制图片不显示的问题

后来观察w3c的案例,和我代码的区别就是他的图片是在html里边的。

然后我就学着向html里边插入了图片,

<img src="./images/background.jpg" id="imgs" style="display:none"></img>

并且用getElementById获取这个元素,

var bgImg = document.getElementById('imgs')

再次执行绘图竟然可以了。

他竟然可以了!

详解canvas drawImage()方法绘制图片不显示的问题

难过的想,就必须要实体吗?不就是放到了canvas标签前边嘛!js加载也有实体啊,而且我还是用new的啊,比真人差哪了!

对啊,不就是放到前边了嘛。这就涉及到一个顺序问题啊!

js里加载的图片是放在绘图前边没错,但是图片加载进来还需要个时间啊。需要给图片缓冲的时间。等图片加载成功后才可以进行绘制。而drawImage这个方法,当图片在没加载完的情况下使用,他会不被调用。绘制就会失败。原来如此!

就有人抬杠说img标签里的图片不需要时间加载吗?这时候drawImage就不受限制了?!但是你不要忽略了,js开头的 window.onload 的啊,就算图片加载再慢,就算图片标签的顺序在canvas标签的后边,但是我有window.onload罩着,我图片加载不完,你drawImage就没戏啊对不对。

大概顺序是这样的:

<img src="">
window.onload = function(){
drawImage
}

如果不是在html结构中插入的图片,就被我的粗心绕过了这个限制:

图片作为一个资源请求,在js中加载时,自然也会有一个图片加载的时间。

但是因为没有限制,极大的情况是当图片还没有加载完毕就调用了drawImage,此方法他是不起作用的。

解决:

那有没有好的方法解决因图片加载顺序导致drawImage绘图失败的情况呢?

我总结了以下三种方法:

1. 标签+window.onload

<img src="">
window.onload = function(){
context.drawImage()
}

这种做法解决的核心是onload,将图片和drawImage分开加载,img先加载,确保加载完毕以后再使用绘图

 1-2. 后期插入标签?是否可行

有一种情况是,使用截图功能时,也可以用drawImage,而截图又不不是截自己既有的图片,而是用一个图片的地址当参数.

我想这种的就需要js来创建一个img,并将地址赋给它.然后生成图片再来截图了

var myImg = document.createElement('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. img.onload

window.onload给了我们思路,直接监听他加载完成不可以了嘛

使用img的加载事件,监听图片加载成功后,再执行canvas的绘图效果.并且这种方法靠谱一些。

bgImg.onload = function(){
     console.log('图片加载成功');
     console.log(this);
     ctx1.drawImage(bgImg,0,0,wWidth,wHeight);
 }

其实这三种方法都是一个核心,就是让图片先加载。即图片预加载。但是对于缓存图片,图片预加载还需要解决的是,当页面不刷新时监听缓存图片的问题。

又发现一个问题。。。。首先,背景图画完的样子长这样。

详解canvas drawImage()方法绘制图片不显示的问题

然后好不容易背景图画出来了,我就开开心心的继续吧。

于是我紧接着画了一条红线,为了避免看不到,我还把宽度增加到了20:

bgImg.onload = function(){
    ctx1.drawImage(bgImg,0,0,wWidth,wHeight);
  }
  /* 绘制红线如下: */
  ctx1.beginPath();
  ctx1.moveTo(10,wHeight);
  ctx1.lineTo(10,wHeight-100);

  ctx1.lineWidth = 20;
  ctx1.strokeStyle = 'red';

  ctx1.stroke();
  ctx1.closePath();

但我F5按下依旧没有变化,还是看不到红线。

找了半天直到我把背景图关掉才看到:

详解canvas drawImage()方法绘制图片不显示的问题

啊,原来他被背景图盖住啦!

可是,为什么呢?

我在想有两种可能

1、层级问题

2、先后问题

关于1,就像css的z-index那种感觉,是背景图在上盖住了红线。难道说背景图的层级比红线高?

这个设想我没法测试,于是放弃进行第二种可能的揭秘。

可是为什么背景图会在上呢?是因为背景图后画?

这个可以最简便的通过console.log()打印观察执行顺序

详解canvas drawImage()方法绘制图片不显示的问题详解canvas drawImage()方法绘制图片不显示的问题

原来“罪魁祸首”竟然是onload这个回调。他跟定时器一样,都是一个异步任务。自然排在了同步任务(下边的绘制线条)的后边

所以前边看似是一个很好的解决方法——onload,在这里也暴露了他的弊端。

很好、看来,promise学习大计宜趁早提上日程啊!哈哈哈

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
CSS3控制HTML元素动画效果
Feb 08 HTML / CSS
用CSS3实现背景渐变的方法
Jul 14 HTML / CSS
CSS3实现背景透明文字不透明的示例代码
Jun 25 HTML / CSS
Css3实现无缝滚动防抖
Sep 14 HTML / CSS
CSS3实现时间轴特效
Nov 02 HTML / CSS
CSS3 按钮边框动画的实现
Nov 12 HTML / CSS
利用canvas实现图片下载功能来实现浏览器兼容问题
May 31 HTML / CSS
html5中canvas学习笔记1-画板的尺寸与实际显示尺寸
Jan 06 HTML / CSS
实例教程 HTML5 Canvas 超炫酷烟花绽放动画实现代码
Nov 05 HTML / CSS
Html5中localStorage存储JSON数据并读取JSON数据的实现方法
Feb 13 HTML / CSS
如何避免常见的6种HTML5错误用法
Nov 06 HTML / CSS
canvas实现漂亮的下雨效果的示例
Apr 18 HTML / CSS
HTML5 和小程序实现拍照图片旋转、压缩和上传功能
Oct 08 #HTML / CSS
传统HTML页面实现模块化加载的方法
Oct 15 #HTML / CSS
html5/css3响应式页面开发总结
Oct 16 #HTML / CSS
教你如何一步一步用Canvas写一个贪吃蛇
Oct 22 #HTML / CSS
HTML高亮关键字的实现代码
Oct 22 #HTML / CSS
详解rem 适配布局
Oct 31 #HTML / CSS
H5 canvas中width、height和style的宽高区别详解
Nov 02 #HTML / CSS
You might like
php延迟静态绑定实例分析
2015/02/08 PHP
PHP中的事务使用实例
2015/05/26 PHP
php从文件夹随机读取文件的方法
2015/06/01 PHP
Zend Framework自定义Helper类相关注意事项总结
2016/03/14 PHP
用PHP去掉文件头的Unicode签名(BOM)方法
2017/06/22 PHP
PHP接口继承及接口多继承原理与实现方法详解
2017/10/18 PHP
PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】
2017/11/14 PHP
jQuery-Tools-overlay 使用介绍
2012/07/14 Javascript
jquery mobile动态添加元素之后不能正确渲染解决方法说明
2014/03/05 Javascript
javascript实现Table间隔色以及选择高亮(和动态切换数据)的方法
2015/05/14 Javascript
js简单网速测试方法完整实例
2015/12/15 Javascript
bootstrap制作jsp页面(根据值让table显示选中)
2017/01/05 Javascript
js实现横向拖拽导航条功能
2017/02/17 Javascript
bootstrap table表格使用方法详解
2017/04/26 Javascript
一步一步实现Vue的响应式(对象观测)
2019/09/02 Javascript
layer弹窗在键盘按回车将反复刷新的实现方法
2019/09/25 Javascript
微信公众号开发之微信支付代码记录的实现
2019/10/16 Javascript
微信小程序实现左滑删除效果
2020/11/18 Javascript
[04:55]完美世界副总裁蔡玮:DOTA2的自由、公平与信任
2013/12/18 DOTA
python使用fileinput模块实现逐行读取文件的方法
2015/04/29 Python
python Django模板的使用方法
2016/01/14 Python
python爬虫之urllib,伪装,超时设置,异常处理的方法
2018/12/19 Python
基于Python在MacOS上安装robotframework-ride
2018/12/28 Python
Python实现的微信红包提醒功能示例
2019/08/22 Python
Pytorch 多块GPU的使用详解
2019/12/31 Python
利用css3 translate完美实现表头固定效果
2017/02/28 HTML / CSS
CSS3 :not()选择器实现最后一行li去除某种css样式
2016/10/19 HTML / CSS
HTML5 history新特性pushState、replaceState及两者的区别
2015/12/26 HTML / CSS
廉价连衣裙和婚纱礼服在线销售:Tbdress
2019/02/28 全球购物
Currentbody西班牙:美容仪专家
2019/09/28 全球购物
幼儿园园长岗位职责
2013/11/26 职场文书
高三生物教学反思
2014/01/25 职场文书
2014年自愿离婚协议书范本
2014/09/25 职场文书
满月酒邀请函
2015/01/30 职场文书
2015年护士节活动策划方案
2015/05/04 职场文书
Go中的条件语句Switch示例详解
2021/08/23 Golang