canvas画图问题,为什么init方法画不出来canvas而render可以画出来

var source = {};
  function load_source(url,w,h,type){//返回图片还是canvas
    this.canvas = document.createElement('canvas');
    this.canvas.width = w;
    this.canvas.height = h;
    this.ctx =this.canvas.getContext('2d');
    this.img = new Image();
  
    this.img.onload = function () {
        this.ctx.drawImage(this.img,0,0);
    }.bind(this);
    this.img.src = url;
    if(type=='canvas')
        return this.canvas;
    else if(type=='img')
        return this.img
}

source.build = new load_source('http://htmljs.b0.upaiyun.com/uploads/1381825919448-6out.png',1024,1024,'canvas');
source.lk = new load_source('http://htmljs.b0.upaiyun.com/uploads/1382543005310-3angles.png',1024,1024,'canvas');
function Map_interpret(){
    this.init = function(){//初始化地图
        this.camera = document.createElement('canvas');//相机
        this.camera.width = 1024;
        this.camera.height = 1024;
        this.ctx = this.camera.getContext('2d');
        document.body.appendChild(this.camera);
         this.ctx.drawImage(source.build,0,0);
    }
    this.render = function(){//初始化地图
        
     this.ctx.drawImage(source.lk,0,0);
    }
    
}
m = new Map_interpret();
m.init();
m.render();

临时写的精简的代码可能会报小错误(思路是图片画到canvas里,再把这个canvas画到另一个canvas里,并显示),主要问题是为什么init方法里面的this.ctx.drawImage(source.build,0,0)画出来的canvas不显示,而render里的this.ctx.drawImage(source.lk,0,0);可以画出来

阅读 5k
5 个回答

说实话,没看懂你在干什么,你load_source函数参数中的type没赋值能返回结果?
还有,把img.src的赋值放到onload函数后面

代码


var source = {};

function Map_interpret(){
    this.camera = document.createElement('canvas');//相机
    this.camera.width = 1024;
    this.camera.height = 1024;
    this.ctx = this.camera.getContext('2d');
    document.body.appendChild(this.camera);

    this.init = function(result){//初始化地图
        this.ctx.drawImage(result,0,0);
    };
    this.render = function(result){//初始化地图
         this.ctx.drawImage(result,0,0);
    };
    
}

var m = new Map_interpret();

function load_source(url,w,h,type,callback){//返回图片还是canvas
    callback = callback || function(){};
    this.canvas = document.createElement('canvas');
    this.canvas.width = w;
    this.canvas.height = h;
    this.ctx =this.canvas.getContext('2d');
    this.img = new Image();

    this.img.onload = function () {
        this.ctx.drawImage(this.img,0,0);
        if(type=='canvas'){
            callback(this.canvas);
        }
        else if(type=='img'){
            callback(this.img);
        }
    }.bind(this);
    this.img.src = url;
}

source.build = new load_source(
    'http://htmljs.b0.upaiyun.com/uploads/1381825919448-6out.png',
    1024,
    1024,
    'canvas',
    function(result){
        m.init(result);
});
source.lk = new load_source(
    'http://htmljs.b0.upaiyun.com/uploads/1382543005310-3angles.png',
    1024,
    1024,
    'canvas',
    function(result){
        m.render(result);
});

我这里给你改得有点多,为了让你看得懂,变量什么的我都没改,你这里为什么绘制不出的原因是load_source这里是个异步函数,在你原程序中有两个地方没处理好:

  1. m.init和m.reader可能在imgload完成之前就已经执行了

  2. 在load_source函数中if语句对type的判断,也就是canvas和img的返回值那里,可能在图片onload完成之前就已经将元素返回

对于异步函数的处理我们目前最好的办法就是回调函数,所以我这里给你加了个回调函数的处理。

下面给你普及点额外知识:

  1. 一般ES5你如果想模拟一个类,类的方法(函数)一般都挂载在原型上面

  2. 当一个方法或者是引用类型的值可能被调用多次的时候,请务必将其保存为局部变量以提高性能。

  3. 对于canvas.width这种dom操作,如果需要频繁用到canvas的大小,请将canvas.width保存到一个变量中以提升性能

当然还有其他的问题,像这种东西只能靠你自己积累,最好是去写一个相关的插件,然后自己给自己找问题,这样提示的速度会更快,以上


source.lk = new load_source(
    'http://htmljs.b0.upaiyun.com/uploads/1382543005310-3angles.png',
    1024,
    1024,
    'canvas',
    function(result){
        m.render(result); //把这里的调用改成将结果传值到循环即可,然后m.render在循环里调用变量就行
});

你的 init 方法里面没有你说的 this.ctx.drawImage(source.build,0,0)。
整个代码里面都没有,只有 render 里的 this.ctx.drawImage(source.lk,0,0)
应该是疏忽了?另外建议好好整理一下,真心不好懂。最好有个可运行例子。

继续回答,你第一步图像放到一号 canvas 的时候有等待图像读取,但是第二步把 canvas 画到第二个 canvas 的时候,没有确认第一步里面的那个一号 canvas 是不是已经有图像。如果这时候图像还没读取成功,一号 canvas 还是空白,那么二号 canvas 自然就是空白。

解决办法有很多,我整理了一下代码,让 source 不再是返回 canvas 或 img, 而是返回包括 canvas img 和 isComplete 的集合,并加入了一个 100 毫秒间隔的图像读取检查。

可运行例子如下:http://runjs.cn/code/7yu6izt0

var imgUrl1 = 'http://img0.bdstatic.com/static/searchresult/img/logo-2X_b99594a.png';
var imgUrl2 = 'http://static.segmentfault.com/v-595f50ca/global/img/logo-b.svg';

var sourceGroup = {};
sourceGroup.source1 = new getCanvasWithImg(imgUrl1);
sourceGroup.source2 = new getCanvasWithImg(imgUrl2);

var map = new Map_interpret();
map.init(sourceGroup.source1);
map.render(sourceGroup.source2);

function getCanvasWithImg(imgUrl) {
    this.canvas = document.createElement('canvas');
    this.img = new Image();
    this.isComplete = false;

    this.img.onload = function() {
        this.canvas.width = this.img.width;
        this.canvas.height = this.img.height;
        this.ctx = this.canvas.getContext('2d');
        this.ctx.drawImage(this.img, 0, 0);
        this.isComplete = true;
    }.bind(this);
    this.img.src = imgUrl;

    return this;
}

function Map_interpret() {
    this.init = function(source) {
        this.camera = document.createElement('canvas');
        this.camera.width = 512;
        this.camera.height = 512;
        this.ctx = this.camera.getContext('2d');
        this.drawAfterComplete(source);

        document.body.appendChild(this.camera);

    }
    this.render = function(source) {
        this.drawAfterComplete(source);
    }
    this.drawAfterComplete = function(source) {//等待读取完毕
        var ctx = this.ctx;
        var checkComplete = setInterval(function() {
            if (source.isComplete) {
                ctx.drawImage(source.img, 0, 0); //source.img 或 source.canvas 看需要
                console.log('!!load complete!!');
                clearInterval(checkComplete);
            } else {
                console.log('NOT complete...')
            }
        }, 100);
    }
}

this.img.onload = function () {

    this.ctx.drawImage(this.img,0,0);
}.bind(this);
this.img.src = url;
if(type=='canvas')
    return this.canvas;
else if(type=='img')
    return this.img

我感觉是这的问题,你确定这样写走到return的时候已经onload了?意思就是你返回canvas的时候还没有调用onload中的drawInage方法嘞;
把判断和返回放到onload函数中试试看
this.img.onload = function () {

    this.ctx.drawImage(this.img,0,0);
    if(type=='canvas')
    return this.canvas;
else if(type=='img')
    return this.img
}.bind(this);
this.img.src = url;

你在每个drawImage前打个log就知道调用顺序了,就知道为什么什么都画不出来了

不要手动创建canvas节点,然后append到html里,因为这个是异步的

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题