EaselJs,“位图”在第一次浏览器加载时无法在登台上显示

Posted

技术标签:

【中文标题】EaselJs,“位图”在第一次浏览器加载时无法在登台上显示【英文标题】:EaselJs, `Bitmap` fails to display on staging on first browser load 【发布时间】:2015-12-21 22:30:47 【问题描述】:

初始化时,我发现我的Bitmap 有时不会显示在staging 上。出于这个原因,我设置了一个 100 毫秒的小超时,这似乎可以解决问题。我正在处理的项目在视频元素顶部有一个画布:顶层和底层。视频元素是网络摄像头流,我在其中捕获快照并将其放置在画布上。画布也可用作遮罩,但在拍摄快照时会独立于视频层进行操作。

在下面的placeMask 方法中,我尝试粘贴Bitmap eventListener added (http://createjs.com/docs/easeljs/classes/Bitmap.html) 以了解图像何时处于暂存状态,然后才请求getUserMedia。这不起作用,到目前为止,仅使用timeout 似乎可以在 100 毫秒内工作(在本地工作,在 100/1000 毫秒下远程测试失败)。本地,尝试了0ms和10ms都没有成功。

我认为这可能与正在加载的图像有关,因此添加了一个在 CanvasImageSnappe 初始化之前发生的预加载器,但没有成功。

另外,当我说第一次浏览器加载时,我的意思是如果用户再次刷新或请求相同的 url,图像就会显示在 staging 中。如果用户打开新窗口或选项卡,则图像无法加载。 100ms 解决了这个问题(在本地工作,远程 1000ms 不起作用)。

下面的代码不完整,但有与问题或上下文相关的方法。

function CanvasImageSnapper() 

    this.init();



CanvasImageSnapper.prototype = 

    init: function () 

        this.setVars();
        this.setListeners();

        // this fix the issue but I'd like to know the reason why
        setTimeout(function () 
            this.placeMask(this.setWebcam.bind(this));
        .bind(this), 100);

    ,


    setVars: function () 

        this.myCanvas = document.querySelector('#myCanvas');
        this.myCanvas.style.width = window.innerWidth + 'px';
        this.myCanvas.style.height = window.innerWidth / (16/9) + 'px';
        this.moduleContainer = document.querySelector('.p-canvas-webcam-prototype');
        this.moduleContainer.style.width = window.innerWidth + 'px';
        this.moduleContainer.style.height = window.innerWidth / (16/9) + 'px';
        this.myCamera = document.querySelector('#my_camera');
        this.videoStream = this.myCamera.querySelector('video');
        this.stage = new createjs.Stage('myCanvas');
        this.stage.canvas.width = parseInt(this.myCanvas.style.width);
        this.stage.canvas.height = parseInt(this.myCanvas.style.height);
        this.ratio = this.stage.canvas.width / this.stage.canvas.height;
        createjs.Touch.enable(this.stage);

        this.el_my_result = document.getElementById('my_result');
        this.el_take_snapshot = document.querySelector('.take_snapshot');
        this.container = new createjs.Container();
        this.handler_container = new createjs.Container();

        this.dragBox = new createjs.Shape(new createjs.Graphics().beginFill("#FFFFFF").drawRect(0, 0, this.stage.canvas.width, this.stage.canvas.height))
        this.dragBox.alpha = 0.01; // hit area needs to be at least `0.01`, but leaving almost transparent to see through
        this.stage.addChild(this.dragBox);

        this.btnPrint = document.querySelector('.btn-print');

        this.snapshot = null;
        this.shape_size =  w: 10, h: 10 ;
        this.maskImage;

        this.btnDownload = document.querySelector('.btn-download');

        this.shapes;

        this.webCamMaxWidth = 1280;
        this.webCamMaxHeight = 720;
        this.webCamSizeRatio = 16 / 9;

        this.snapshots = [];

        this.el_remove_snapshot = document.querySelector('.remove_snapshot');

        this.galleryThemes = document.querySelectorAll('.gallery-selector ul li');

        this.maskName = 'mask_01';

        // cache
        this.cached = 
            images: 
                'mask_01': new createjs.Bitmap('img/mask_01.png'),
                'mask_02': new createjs.Bitmap('img/mask_02.png'),
                'mask_03': new createjs.Bitmap('img/mask_03.png'),
            
        ;

        // mandrill api key
        this.mandrillApiKey = 'xxxxxxxxxxx';

    ,


    setListeners: function () 

        // disable to improve performance
        //createjs.Ticker.addEventListener("tick", this.tickHandler.bind(this));

        this.el_take_snapshot.addEventListener('click', this.snapHandler.bind(this));

        this.dragBox.addEventListener("mousedown", function (event) 

            var offset = new createjs.Point();

            offset.x = this.stage.mouseX - this.container.x;
            offset.y = this.stage.mouseY - this.container.y;

            event.target.addEventListener("pressmove", function (event) 

                this.container.x = event.stageX - offset.x;
                this.container.y = event.stageY - offset.y;

                this.handler_container.x = this.container.x;
                this.handler_container.y = this.container.y;

                this.stage.update();

            .bind(this));

        .bind(this));

        this.btnPrint.addEventListener('click', function (e) 
            this.print();
        .bind(this));

        window.addEventListener('resize', this.winResizeHandler.bind(this));

        this.btnDownload.addEventListener('click', function () 
            this.hideHandlers();
            this.downloadImg();
        .bind(this));

        window.addEventListener('showHandlers', function () 

            this.handler_container.alpha = 1;

            this.stage.update();

        .bind(this));

        Webcam.on('load', function () 

            this.camFitToScale();

        .bind(this));

        this.el_remove_snapshot.addEventListener('click', function () 
            this.removeShapshotHandler.call(this);
        .bind(this));

        var context = this;
        for (var i = 0; i < this.galleryThemes.length; i++) 
            this.galleryThemes[i].addEventListener('click', function () 

                // clear existing
                if (context.maskImage) 
                    context.stage.removeChild(context.maskImage);
                    context.stage.update();
                

                context.maskName = this.getAttribute('data-mask-name');

                context.placeMask.call(context, false);

            );
        

    ,

    placeMask: function (callback) 

        this.maskImage = this.cached.images[this.maskName];

        this.maskImage.scaleX = parseInt(this.myCanvas.style.width) / this.maskImage.image.width;
        this.maskImage.scaleY = parseInt(this.myCanvas.style.height) / this.maskImage.image.height;

        this.stage.addChild(this.maskImage);

        this.stage.update();

        if (typeof callback === "function") 

            callback.call(this);

        

    


为了清楚预加载器,我附上了代码,这样我的意图就很清楚了。我不知道这是否有帮助,因为可能在 Bitmap 构造函数上加载图像会再次获取图像,而忽略任何浏览器缓存?

var arrImgList = ['img/mask_01.png', 'img/mask_02.png', 'img/mask_03.png'];

imagesLoaded(arrImgList, function( instance ) 
    var canvasImageSnapper = new CanvasImageSnapper();
    window.canvasImageSnapper = canvasImageSnapper;
);

你可以在这里找到完整的代码:http://pastie.org/private/371jvrb5i1vmtz0e28bnvw

【问题讨论】:

【参考方案1】:

听起来仍然像是图像的(预)加载错误 - 但我不太确定,imagesLoaded 在做什么?!您是否尝试过先预加载位图并使用 Image-Object 创建位图?

var img1 = new Image();
img.onload = function() 
  var bitmap = new createjs.Bitmap(img1);
  ...
;
img.src = 'path/to/img.png';

【讨论】:

感谢您的评论!确实是在预加载图像。 imagesLoaded 预加载图像,但您的方法更好,因为将节点图像注入位图构造函数就可以了。我会用我为此做的代码留下答案。 所以我认为问题在于,尽管您使用imagesLoded 预加载图像,但它会重新加载图像,因为您基本上是在使用每个新的Image 创建一个新的Image 实例@(但是它可能仍会从缓存中加载图像,但您不能确定...)。如果你有更多的东西要预加载(比如 json 等),可能值得看看 PreloadJS createjs.com/docs/preloadjs ;) 谢谢德雷兹!有道理!【参考方案2】:

根据derz 的回答,解决方案如下:

        // preload
        var arrImgList = ['img/mask_01.png', 'img/mask_02.png', 'img/mask_03.png'],
            loaded = 0;

        for (var i = 0; i < arrImgList.length; i++) 

            var img = new Image();

            img.addEventListener('load', function () 

                loaded = loaded + 1;

                if (loaded === Object.keys(this.cached.images).length) 
                    this.placeMask(this.setWebcam.bind(this));
                

            .bind(this));

            img.src = arrImgList[i];
            this.cached.images['mask_0' + (i + 1)] = new createjs.Bitmap(img);
        

【讨论】:

以上是关于EaselJs,“位图”在第一次浏览器加载时无法在登台上显示的主要内容,如果未能解决你的问题,请参考以下文章

EaselJS (0.8.2.min 及以上)- 当角色移动时移动 JSON 生成的 Sprite 贴图 XY

EaselJS:在属性更改时更新形状颜色

无法加载多个位图 - WinAPI [重复]

无法从资源加载位图

如何使用 Easeljs 处理 iPhone 上的快速点击?

如何在easeljs中管理多个场景?