使用文本将多个SVG保存到画布,然后获取dataURL

时间:2015-09-29 21:16:28

标签: javascript angularjs html5 canvas svg

我已经构建了一个angularJS应用程序,在这个应用程序中,SVG文件代表用户选择的服装。我有一个下载按钮(当前)将第一个SVG作为PNG保存到数据库中,我使用视图来显示这个"预览"。

我创建的指令如下所示:

.directive('kdExport', function () {

    return {
        restrict: 'A',
        scope: {
            target: '@kdExport',
            team: '='
        },
        controller: 'ExportImageController',
        link: function (scope, element, attrs, controller) {

            console.log(scope.team);

            // Bind to the onclick event of our button
            element.bind('click', function (e) {

                // Prevent the default action
                e.preventDefault();

                // Generate the image
                controller.generateImage(scope.target, scope.team, function (preview) {

                    // Create our url
                    var url = '/kits/preview/' + preview.id;

                    // Open a new window
                    window.open(url, '_blank');
                });
            });
        }
    };
})

,控制器如下所示:

.controller('ExportImageController', ['PreviewService', function (service) {
    var self = this;

    // Function to remove the hidden layers of an SVG document
    var removeHidden = function (element) {

        // Get the element children
        var children = element.children(),
            i = children.length;

        // If we have any children
        if (children.length) {

            // For each child
            for (i; i >= 0; i--) {

                // Get our child
                var child = angular.element(children[i - 1]);

                // Remove hidden from the child's children
                removeHidden(child);

                // Finally, if this child has the class "hidden"
                if (child.hasClass("hidden")) {

                    // Remove the child
                    child.remove();
                }
            }
        }
    };

    // Public function to generate the image
    self.generateImage = function (element, team, onSuccess) {

        // Get our SVG
        var target = document.getElementById(element),
            container = target.getElementsByClassName('svg-document')[0],
            clone = container.cloneNode(true);

        // Remove hidden layers
        removeHidden(angular.element(clone));

        // Create our data
        var data = clone.innerHTML,
            svg = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });

        // Get our context
        var canvas = document.getElementById('canvas'),
            ctx = canvas.getContext('2d');

        // Create our image
        var DOMURL = window.URL || window.webkitURL || window,
            url = DOMURL.createObjectURL(svg),
            img = new Image();

        // When the image has loaded
        img.onload = function () {

            canvas.width = 1000;
            canvas.height = 500;

            // Draw our image using the context
            ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, 1000, 500);
            DOMURL.revokeObjectURL(url);

            // Get our URL as a base64 string
            var dataURL = canvas.toDataURL("image/png");

            // Create our model
            var model = {
                teamName: team.name,
                sport: team.sport,
                data: dataURL
            };

            // Create our preview
            service.create(model).then(function (response) {

                // Invoke our success callback
                onSuccess(response);
            });
        }

        // Set the URL of the image
        img.src = url;
    };
}])

这适用于单个SVG文档,但现在客户端已经要求我为多个SVG执行此操作,每个SVG都有一个标题,并且他们希望将它们全部放在一个PNG中。 我没有做过很多关于画布的工作,所以我不确定是否可以做到这一点。 有谁知道我怎么做到这一点?

1 个答案:

答案 0 :(得分:0)

好的,所以我自己用承诺来解决这个问题。 基本上我创建了一个名为 drawImage 的方法,它允许我为每个SVG绘制一个图像。 为了确保在调用 toDataURL 之前绘制了所有图像,我使该函数返回承诺,一旦图像加载我已解决 即可。 然后我只使用 $ q.all 来获取dataURL并将数据保存到我的数据库中。 方法看起来像这样:

// Private function for drawing our images
var drawImage = function (canvas, ctx, clone) {

    // Defer our promise
    var deferred = $q.defer();

    // Create our data
    var data = clone.innerHTML,
        svg = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });

    // Create our image
    var DOMURL = window.URL || window.webkitURL || window,
        url = DOMURL.createObjectURL(svg),
        img = new Image();

    // When the image has loaded
    img.onload = function () {

        // Get our location
        getNextLocation(canvas.width, canvas.height, img);

        // Draw our image using the context (Only draws half the image because I don't want to show the back)
        ctx.drawImage(img, 0, 0, img.width / 2, img.height, location.x, location.y, location.width, location.height);
        DOMURL.revokeObjectURL(url);

        // Resolve our promise
        deferred.resolve();
    }

    // Set the URL of the image
    img.src = url;

    // Return our promise
    return deferred.promise;
};

// Public function to generate the image
self.generateImage = function (element, team, onSuccess) {

    // Get our SVG
    var target = document.getElementById('totals'),
        containers = angular.element(target.getElementsByClassName('svg-document'));

    // Get our context
    var canvas = document.getElementById('canvas'),
        ctx = canvas.getContext('2d');

    // Set our canvas height and width
    canvas.width = 2000;
    canvas.height = calculateCanvasHeight(containers.length);

    // Create our array of promises
    var promises = [];

    // For each container
    for (var i = 0; i < containers.length; i++) {

        // Get our container
        var container = containers[i],
            clone = container.cloneNode(true);

        // Remove hidden layers
        removeHidden(angular.element(clone));

        // Add our promise to the array
        promises.push(drawImage(canvas, ctx, clone));
    }

    // When all promises have resolve
    $q.all(promises).then(function () {

        // Get our URL as a base64 string
        var dataURL = canvas.toDataURL("image/png");

        // Create our model
        var model = {
            teamName: team.name,
            sport: team.sport,
            data: dataURL
        };

        // Create our preview
        self.create(model).then(function (response) {

            // Invoke our success callback
            onSuccess(response);
        });

    })
};

显然这里缺少代码,但是这段代码解决了我的问题,其余的只是让我的服务工作:)