Сохранение нескольких SVG на холст с текстом с последующим получением dataURL

0

Я создал приложение 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 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 с заголовком под каждым, и они хотят все это в одном PNG. Я не проделал много работы с canvasing, поэтому я не уверен, что это можно сделать. Кто-нибудь знает, как я могу это достичь?

  • 0
    Просто создайте переменную, которую вы будете увеличивать при каждой загрузке изображения, и вызывайте toDataURL () только тогда, когда эта variable === svgDocs.length-1 . Кроме того, вам не нужно создавать Blobs и ObjectUrls для рисования ваших svgs, достаточно простого dataURL (вы можете использовать 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(new XMLSerializer().serializeToString(yourSVGElement)) ).
Теги:
svg
canvas

1 ответ

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);
        });

    })
};

Очевидно, что здесь отсутствует код, но этот код отвечает на мою проблему, остальное просто заставляет мою службу работать :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню