【问题标题】:How to post immediately after svg to canvas conversion is done?如何在 svg 到画布转换完成后立即发布?
【发布时间】:2015-06-20 12:22:13
【问题描述】:

在将 html 元素中的所有 svg 转换为画布后,我正在尝试使用 html2canvas 发布,但该帖子在 svg 到画布转换完成之前立即执行,因为它需要几秒钟。我尝试过使用 deferred 和 Promise,但我仍然遇到同样的问题。

    // https://github.com/niklasvh/html2canvas/issues/95#issuecomment-45114424
    // First render all SVGs to canvases
    targetElem = $('#dashboard');

    var elements = targetElem.find('svg').map(function() {
        var svg = $(this);
        var canvas = $('<canvas></canvas>');
        svg.replaceWith(canvas);

        // Get the raw SVG string and curate it
        var content = svg.wrap('<p></p>').parent().html();
        content = content.replace(/xlink:title='hide\/show'/g, '');
        content = encodeURIComponent(content);
        svg.unwrap();

        // Create an image from the svg
        var image = new Image();
        image.src = 'data:image/svg+xml,' + content;
        image.onload = function() {
            canvas[0].width = image.width;
            canvas[0].height = image.height;

            // Render the image to the canvas
            var context = canvas[0].getContext('2d');
            context.drawImage(image, 0, 0);
        };

        return {
            svg: svg,
            canvas: canvas
        };
    }); // end of targetElem.find('svg').map(function() {...});

已编辑:这是我一直在尝试实现的延迟和承诺,以创建两个按顺序运行的操作。

$(document).ready(function() {

    $( '#save_dashboard' ).click(function() {

    // Create a deferred object
    var dfd = $.Deferred();

        // https://github.com/niklasvh/html2canvas/issues/95#issuecomment-45114424
        // First render all SVGs to canvases
        targetElem = $('#dashboard');

        var elements = targetElem.find('svg').map(function() {
            var svg = $(this);
            var canvas = $('<canvas></canvas>');
            svg.replaceWith(canvas);

            // Get the raw SVG string and curate it
            var content = svg.wrap('<p></p>').parent().html();
            content = content.replace(/xlink:title='hide\/show'/g, '');
            content = encodeURIComponent(content);
            svg.unwrap();

            // Create an image from the svg
            var image = new Image();
            image.src = 'data:image/svg+xml,' + content;
            image.onload = function() {
                canvas[0].width = image.width;
                canvas[0].height = image.height;

                // Render the image to the canvas
                var context = canvas[0].getContext('2d');
                context.drawImage(image, 0, 0);
            };
            dfd.resolve();

            return dfd.promise();
            };
        }); // end of targetElem.find('svg').map(function() {...});

        dfd.resolve();

        $.when(dfd).done(function(){
            console.log('dfd done');

            // http://www.kubilayerdogan.net/html2canvas-take-screenshot-of-web-page-and-save-it-to-server-javascript-and-php/
            $('#dashboard').html2canvas({
                onrendered: function (canvas) {
                    //Set hidden field's value to image data (base-64 string)
                    var dashboardPng = canvas.toDataURL('image/png');
                    console.log('dashboardPng: ' + dashboardPng);

                    $.ajax({
                        url:'save_dashboard_image.php',
                        data:{dashboardPngData: dashboardPng},
                        type:'POST',
                        dataType:'json',
                        success: function(){
                            console.log('success');
                        }
                        ,
                        error: function(xhr, status, error){
                            console.log('The requested page was: ' + document.URL +
                                '. The error number returned was: ' + xhr.status +
                                '. The error message was: ' + error);
                        }
                    });
                }
            });
        }); // end of $.when(dfd).done(...)
    }); // end of save_dashboard click function
}); // end of document ready

【问题讨论】:

  • 可以包含 html , "post" js "我在将 svgs 转换为画布后尝试运行 post,但在转换完成之前立即执行 post"elements jQuery object 或 array 的预期返回值是什么?可以创建stacksn-ps blog.stackoverflow.com/2014/09/… , jsfiddle jsfiddle.net 来演示吗?
  • 代码是异步的,所以你需要使用回调/承诺。你说你尝试过承诺,你能展示一下代码吗?
  • @Ken Fyrstenberg 我已经更新了我迄今为止尝试过的承诺。

标签: javascript jquery canvas svg html2canvas


【解决方案1】:

更新

注意,未经测试。调整click事件返回多个canvas,promise对象,到.then()

如果正确解释问题,请尝试

$(document).ready(function() {

    $( '#save_dashboard' ).click(function() {

    // Create a deferred object
    // dfd = new $.Deferred();

        // https://github.com/niklasvh/html2canvas/issues/95#issuecomment-45114424
        // First render all SVGs to canvases
        targetElem = $('#dashboard');
        var promises = $.when.apply(targetElem, $.map(targetElem.find('svg')
          , function(el, index) {
            return new $.Deferred(function(dfd) {
              var svg = $(el);
              var canvas = $('<canvas></canvas>');
              svg.replaceWith(canvas);

              // Get the raw SVG string and curate it
              var content = svg.wrap('<p></p>').parent().html();
              content = content.replace(/xlink:title='hide\/show'/g, '');
              content = encodeURIComponent(content);
              svg.unwrap();

              // Create an image from the svg
              var image = new Image();

              image.onload = function() {
                  canvas[0].width = image.width;
                  canvas[0].height = image.height;

                  // Render the image to the canvas
                  var context = canvas[0].getContext('2d');

                  dfd.resolve(context.drawImage(image, 0, 0));
              };
              image.src = 'data:image/svg+xml,' + content;
            }).promise();          
          })
         ); // end of targetElem.find('svg').map(function() {...});



        promises.then(function(_canvas) {
            console.log('dfd done', _canvas, arguments);

            // http://www.kubilayerdogan.net/html2canvas-take-screenshot-of-web-page-and-save-it-to-server-javascript-and-php/
            $('#dashboard').html2canvas({
                onrendered: function (canvas) {
                    //Set hidden field's value to image data (base-64 string)
                    var dashboardPng = canvas.toDataURL('image/png');
                    console.log('dashboardPng: ' + dashboardPng);

                    $.ajax({
                        url:'save_dashboard_image.php',
                        data:{dashboardPngData: dashboardPng},
                        type:'POST',
                        dataType:'json',
                        success: function(){
                            console.log('success');
                        }
                        ,
                        error: function(xhr, status, error){
                            console.log('The requested page was: ' + document.URL +
                                '. The error number returned was: ' + xhr.status +
                                '. The error message was: ' + error);
                        }
                    });
                }
            });
        }); // end of $.when(dfd).done(...)
    }); // end of save_dashboard click function
}); // end of document 

【讨论】:

  • 所以它适用于您的实现。看起来我需要传递正在解决的问题。你在 dfd.then(function(_canvas) { console.log('dfd done', _canvas); 中使用 _canvas 有什么原因吗?我猜在这种情况下 deferred.then 可以在这里使用,因为 deferred.then 立即执行,但是在 drawImage() 完成之前不会被解析。
  • 似乎在将第一个 svg 转换为画布并发布后触发的解析仅在该点捕获第一个 svg。如何解决整个转换过程?
  • @user2120512 "你在 dfd.then(function(_canvas) { console.log('dfd done', _canvas); 中使用 _canvas 有什么原因吗?》 做了/没有实际实现的 stacksn-ps / jsfiddle - 包括html。不确定是否从elements 循环返回promise 值将/可以在.then() 使用。
  • @user2120512 是否应该为每个返回的承诺值调用$('#dashboard').html2canvas({})
  • 是的,每个都比地图更有意义。
【解决方案2】:

解决方案我必须为每个连续的 svg 到画布转换以及它们都完成时使用一个数组。我可以将数组传递给 then() 以发布 html2canvas。

  1. 点击时创建一个新数组,用它来存储来自 SVG 的所有延迟
  2. 循环遍历所有 SVG 元素
    • 在每个实例中,创建一个新的内部延迟对象
    • 解决或拒绝延期
    • 将其推入循环外的数组中
  3. 使用$.when.apply($, arrayOfDeferredObjects) 检查数组中所有延迟对象的状态

    $( '#save_dashboard' ).click(function() {
    
        // Declare an array to store all deferred objects from each svg element
        var svgDfds = [],
            targetElem = $('#dashboard');
    
        targetElem.find('svg').each(function() {
            var dfd = new $.Deferred(),
                svg = $(this),
                canvas = $('<canvas></canvas>');
    
            svg.replaceWith(canvas);
    
            // Get the raw SVG string and curate it
            var content = svg.wrap('<p></p>').parent().html();
            content = content.replace(/xlink:title='hide\/show'/g, '');
            content = encodeURIComponent(content);
            svg.unwrap();
    
            // Create an image from the svg
            var image = new Image();
            image.src = 'data:image/svg+xml,' + content;
            image.onload = function() {
                canvas[0].width = image.width;
                canvas[0].height = image.height;
    
                // Render the image to the canvas
                var context = canvas[0].getContext('2d');
    
                // Resolve or reject the deferred
                dfd.resolve(context.drawImage(image, 0, 0));
            };
    
            // Push deferred object into array
            svgDfds.push(dfd);
    
        }); // end of targetElem.find('svg').map(function() {...});
    
        // Check for all deferreds
        $.when.apply($, svgDfds).then(function(_canvas) {
            console.log('dfd done', _canvas);
    
            // http://www.kubilayerdogan.net/html2canvas-take-screenshot-of-web-page-and-save-it-to-server-javascript-and-php/
            $('#dashboard').html2canvas({
                onrendered: function (canvas) {
                    //Set hidden field's value to image data (base-64 string)
                    var dashboardPng = canvas.toDataURL('image/png');
                    console.log('dashboardPng: ' + dashboardPng);
    
                    $.ajax({
                        url:'save_dashboard_image.php',
                        data:{dashboardPngData: dashboardPng},
                        type:'POST',
                        dataType:'json',
                        success: function(){
                            console.log('success');
                        }
                        ,
                        error: function(xhr, status, error){
                            console.log('The requested page was: ' + document.URL +
                                '. The error number returned was: ' + xhr.status +
                                '. The error message was: ' + error);
                        }
                    });
                }
            });
        });
    
    }); // end of save_dashboard click function
    

【讨论】:

  • 能否描述此解决方案与上述更新帖子中的解决方案之间的区别?
  • 我已经更新了在您的帮助下找到的解决方案之间的差异。
猜你喜欢
  • 2019-12-29
  • 1970-01-01
  • 2013-03-22
  • 2020-07-09
  • 2021-11-23
  • 2018-08-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多