EaselJs,“位图”无法在首次浏览器加载时显示在暂存区
EaselJs, `Bitmap` fails to display on staging on first browser load
初始化时我发现 Bitmap
有时不显示在 staging
上。出于这个原因,我设置了一个 100 毫秒的小超时,这似乎可以解决问题。我正在处理的项目在视频元素之上有一个 canvas:顶层和底层。视频元素是网络摄像头流,我在其中捕获快照并将其放在 canvas 上。 canvas 也可用作遮罩,但在拍摄快照时独立于视频层进行操作。
在下面的 placeMask
方法中,我尝试添加一个 Bitmap
eventListener added
(http://createjs.com/docs/easeljs/classes/Bitmap.html) 以了解图像何时在暂存中,然后才请求获取用户媒体。这没有用,到目前为止仅使用 timeout
似乎可以在 100 毫秒内工作(在本地工作,使用 100/1000 毫秒进行远程测试失败)。在本地,尝试了 0ms 和 10ms 都没有成功。
我认为这可能与正在加载的图像有关,因此添加了一个在 CanvasImageSnappe
初始化之前发生的预加载器,但没有成功。
此外,当我说第一次浏览器加载时,我的意思是如果用户再次刷新或请求相同的 url,图像将显示在暂存中。如果用户打开新的 window 或选项卡,图像将无法加载。 100 毫秒解决了这个问题(在本地工作,远程 1000 毫秒不起作用)。
下面的代码不完整,但有与问题或上下文相关的方法。
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
听起来仍然像是图像的(预)加载错误 - 但是我不太确定 imagesLoaded
在做什么?!您是否尝试过先预加载位图并使用 Image
-Object 创建位图?
var img1 = new Image();
img.onload = function(){
var bitmap = new createjs.Bitmap(img1);
...
};
img.src = 'path/to/img.png';
根据 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);
}
初始化时我发现 Bitmap
有时不显示在 staging
上。出于这个原因,我设置了一个 100 毫秒的小超时,这似乎可以解决问题。我正在处理的项目在视频元素之上有一个 canvas:顶层和底层。视频元素是网络摄像头流,我在其中捕获快照并将其放在 canvas 上。 canvas 也可用作遮罩,但在拍摄快照时独立于视频层进行操作。
在下面的 placeMask
方法中,我尝试添加一个 Bitmap
eventListener added
(http://createjs.com/docs/easeljs/classes/Bitmap.html) 以了解图像何时在暂存中,然后才请求获取用户媒体。这没有用,到目前为止仅使用 timeout
似乎可以在 100 毫秒内工作(在本地工作,使用 100/1000 毫秒进行远程测试失败)。在本地,尝试了 0ms 和 10ms 都没有成功。
我认为这可能与正在加载的图像有关,因此添加了一个在 CanvasImageSnappe
初始化之前发生的预加载器,但没有成功。
此外,当我说第一次浏览器加载时,我的意思是如果用户再次刷新或请求相同的 url,图像将显示在暂存中。如果用户打开新的 window 或选项卡,图像将无法加载。 100 毫秒解决了这个问题(在本地工作,远程 1000 毫秒不起作用)。
下面的代码不完整,但有与问题或上下文相关的方法。
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
听起来仍然像是图像的(预)加载错误 - 但是我不太确定 imagesLoaded
在做什么?!您是否尝试过先预加载位图并使用 Image
-Object 创建位图?
var img1 = new Image();
img.onload = function(){
var bitmap = new createjs.Bitmap(img1);
...
};
img.src = 'path/to/img.png';
根据 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);
}