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的关键属性名及方法再检查一遍,确实没错啊。
图片打印出来,也有这个(人)图啊!

后来观察w3c的案例,和我代码的区别就是他的图片是在html里边的。
然后我就学着向html里边插入了图片,
<img src="./images/background.jpg" id="imgs" style="display:none"></img>
并且用getElementById获取这个元素,
var bgImg = document.getElementById('imgs')

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

他竟然可以了!
 
难过的想,就必须要实体吗?不就是放到了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任务执行中,你嫌我离你执行的时间太近是不,那把我单独拎出来重新排队,等会再执行可以否?(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);
}
其实这三种方法都是一个核心,就是让图片先加载。即图片预加载。
但是对于缓存图片,图片预加载还需要解决的是,当页面不刷新时监听缓存图片的问题,这个问题另一篇博文
 
又发现一个问题。。。。
首先,背景图画完的样子长这样。

然后好不容易背景图画出来了,我就开开心心的继续吧。
于是我紧接着画了一条红线,为了避免看不到,我还把宽度增加到了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按下依旧没有变化,还是看不到红线。

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

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

可是,为什么呢?

我在想有两种可能

1、层级问题

2、先后问题

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

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

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

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

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

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

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

2018-09-28  12:38:03 

canvas - drawImage()方法绘制图片不显示的问题的更多相关文章

  1. <canvas>drawImage()方法无法显示图片

    在书上看到用<canvas>绘制图像就动手试试,刚开始,我的代码是这样的: <!DOCTYPE html> <html> <head> <meta ...

  2. Canvas中 drawImage绘制图片不显示

    在学习 html5中的 Canvas.drawImage时写了如下代码: <!doctype html> <html> <head><title>研究& ...

  3. Android Canvas使用drawBitmap绘制图片

    1.基本的绘制图片方法 //Bitmap:图片对象,left:偏移左边的位置,top: 偏移顶部的位置 drawBitmap(Bitmap bitmap, float left, float top, ...

  4. android中Canvas使用drawBitmap绘制图片

    1.主要的绘制图片方法 //Bitmap:图片对象,left:偏移左边的位置,top: 偏移顶部的位置     drawBitmap(Bitmap bitmap, float left, float ...

  5. 使用canvas 的api 实现 图片的显示 及 压缩

    在移动端压缩图片并且上传主要用到filereader.canvas 以及 formdata 这三个h5的api.逻辑并不难.整个过程就是: (1)用户使用input file上传图片的时候,用file ...

  6. canvas drawImage方法不显示图片的解决方案

    先复习一下用法: context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height); 各个参数说明: 参数 描述 img 规定要使用的图像.画布 ...

  7. 关于Chrome和Opera中draw Image()方法无法在canvas画布中绘制图片的问题

    var c=document.getElementById("myCanvas"); var ctx=c.getContext("2d"); var img=d ...

  8. HTML5 Canvas 绘制图片不显示的问题

    问题: 慕名赶来,却一脚踩空,低头一看,地上一个大坑. 事情是这样的,在我看完w3c的介绍和很有说服力和教学力的demo后,本着实践出真知的思想决定上手一试,这一试不要紧~ 我按照流水线工程铺设以下几 ...

  9. canvas.drawImage()方法详解

    首先看html5.js /**@param {Element} img_elem@param {Number} dx_or_sx@param {Number} dy_or_sy@param {Numb ...

随机推荐

  1. HttpURLConnection 发送 文件和字符串信息

    以文件的形式传参/**     * 通过拼接的方式构造请求内容,实现参数传输以及文件传输     *      * @param actionUrl 访问的服务器URL     * @param pa ...

  2. poj 1700 Crossing River C++/Java

    http://poj.org/problem?id=1700 题目大意: 有n个人要过坐船过河,每一个人划船有个时间a[i],每次最多两个人坐一条船过河.且过河时间为两个人中速度慢的,求n个人过河的最 ...

  3. server2008,本机可以登录ftp,其他机器登录不了解决办法。肯定是防火墙的问题

    转自http://kkworms.blog.51cto.com/540865/558477 今天在windows server 2008 R2上安装了FTP,安装过程如下,然后添加内置防火墙设置,设置 ...

  4. C# 文件过滤器filter

    OpenFileDialog对话框的Filter属性说明: 首先说明一个示例,分析一下Filter属性的构成:“ Excel文件|*.xls ”,前面的“Excel文件”成为标签,是一个可读的字符串, ...

  5. The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead [duplicate]

    From: http://stackoverflow.com/questions/13944956/the-mysql-extension-is-deprecated-and-will-be-remo ...

  6. MATLAB:读取txt文件中物体的三维坐标,显示三维模型

    在MATLAB中建立一个脚本show3Dtxt.m文件,编写代码: clear; %%read 3D data fileID= fopen('E:\博士\深度学习与三维重建\代码实现\voxel_gr ...

  7. Mac或者linux下登陆到linux上的SFTP

    登陆 sftp  -i  密钥路径  用户@ip ➜  ~ sftp -i Desktop/aliyun.pem root@39.106.30.1 Connected to 39.106.30.1 上 ...

  8. 源码分析七(java.lang包之IllegalArgumentException类)

    一:IllegalArgumentException非法参数类,这个类继承父类RuntimeException public class IllegalArgumentException extend ...

  9. springboot+elasticsearch配置实现

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  10. Layui:设置select下拉框自动选中某项

    1.问题:layUI,在做编辑功能有下拉框数据时,需要初始化选中某个值,layUI官网没有相关api,可能我比较笨没找到 2.解决思路:出发点击事件 3.分析dom树结构,出发dl点击事件 方法: v ...