使用Canvas和ForEach处理异步调用

Handling Async Calls with Canvas and ForEach

本文关键字:异步 调用 处理 ForEach Canvas 使用      更新时间:2023-09-26

我正在努力了解如何利用angular的$q库来显示基于画布绘图的图像,然后使用.toDataURL()进行转换;

基本上我想:

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

问题是,函数.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;">

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

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更改为数组,而不是对象,但如果您需要的话,返回使用对象应该不会太困难。