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


    问题:

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

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

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

    1. canvas标签+id

        <div >
            <canvas id="myCanvas2" width="700" height="400" style="border:1px solid #c3c3c3;">
                Your browser does not support the canvas element.
            </canvas>
        </div>

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

                var c2 = document.getElementById("myCanvas2");
                var cxt2 = c2.getContext("2d");

    3. new一个Image()对象,并付给他的属性

                var img = new Image();
                img.src = "canvasTest1.jpg";

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

    cxt2.drawImage(img,30,20,640,360);

    流着哈喇子,我在浏览器按下了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任务执行中,你嫌我离你执行的时间太近是不,那把我单独拎出来重新排队,等会再执行可以否?

    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的绘图效果.并且这种方法靠谱一些。

                img.onload = function() {
                    console.log("图片加载完成!");
                    cxt2.drawImage(img,30,20,640,360);
                }

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

  • 相关阅读:
    oracle 索引
    oracle 子查询因子化 浅谈(with的使用)
    大数据的遐想
    数据挖掘(算法概要链接)
    orcale 修改字段属性
    sql 对一张表进行按照不同条件进行多次统计
    oracle dblink
    oracle作业
    SQL效率的几点心得
    提高SQL语句的性能
  • 原文地址:https://www.cnblogs.com/zhurong/p/10492766.html
Copyright © 2020-2023  润新知