使用Canvas和ForEach处理异步调用

时间:2015-02-25 13:12:32

标签: javascript angularjs html5 canvas asynchronous

我试图理解如何利用角度的$ q库来显示基于画布图的图像,然后使用.toDataURL()进行转换;

基本上我想:

  1. 循环图像($scope.targetImages
  2. 在画布上绘制
  3. 使用.toDataURL()将它们转换为图像并将其存储在($scope.outputImages);
  4. 使用ng-repeat
  5. 显示图像

    问题是,函数.toDataURL()在执行之前可能需要一些时间,从而导致步骤4的延迟调用,因此没有显示任何内容。

    我尝试过以下操作,但在转换完所有图像之前它仍然会解决。

    正如我现在所做的那样,当我第二次拨打drawCanvas()时,会显示图像。

        // 1
        $scope.targetImages= {}
    
        drawCanvas().then(function(data){
          console.log("done: " + new Date())
          console.log(data)
          $scope.outputImages = data;
          $scope.previewMode = false; // switch views, display canvas, remove preview
        });
    
    
        function drawCanvas() {
    
        var defer = $q.defer();
    
        var targetImages = {} 
        angular.forEach($scope.targetImages , function(imageObj, key) {
    
          var canvas = document.getElementById("canvas");
          var ctx = canvas.getContext("2d");
          var img = new Image();
          img.src = imageObj.nativeURL;
          img.onload = start
    
          // 2
          function start() {
    
            ctx.drawImage(img, 0, 0, img.width, img.height);
    
            outputImages[key] = {
              IID: key,
              dataURL: canvas.toDataURL()
            }
    
          } // start
    
        }); // for loop target images
    
        defer.resolve(outputImages);
        return defer.promise;
    
        } // draw canvas
    

    显示为:

    <img ng-show="!previewMode" ng-src="{{image.dataURL || ''}}" style="width: 100vw; max-width: 600px;">
    

1 个答案:

答案 0 :(得分:2)

首先,定义一个将图像绘制到画布并返回结果的承诺的函数:

function drawToCanvas(nativeURL) {
    return $q(function (resolve) {
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        var img = new Image();

        img.src = nativeURL;
        img.onload = function () {
            ctx.drawImage(img, 0, 0, img.width, img.height);

            resolve(canvas.toDataURL());
        };
    });
}

然后解决方案变为:

$scope.targetImages = [];

function drawCanvas() {
    // pResults is an array of promises
    var pResults = $scope.targetImages.map(function (imageObj) {
        return drawToCanvas(imageObj.nativeURL);
    });

    return $q.all(pResults);
}

drawCanvas().then(function(data) {
    // data is an array of imageUrls
    console.log("done: " + new Date())
    console.log(data)
    $scope.outputImages = data;
    $scope.previewMode = false; 
    // switch views, display canvas, remove preview
});

为了简化,我将$scope.targetImages$scope.outputImages更改为数组而不是对象,但如果这是您需要的话,那么回到使用对象应该不会太难。< / p>