2017-02-09 19 views
0

編輯:創建一個外部模板我的指令出口SVG爲PNG使用d3js-wordcloud角指令

我想實現一個簡單的下載/導出功能,將轉換和保存渲染SVG詞雲作爲我的Angular應用程序中的png。

我正在使用Jason Davies完成的d3單詞雲生成器和Julien Renaux的簡化腳本。

我想添加一個簡單的導出功能,使用iweczek的保存-SVG-AS-的圖像導出功能(http://techslides.com/save-svg-as-an-image),而是介於我失去了一些東西。

這是我的角度WordCloud指令,包括底部的導出功能(scope.exportToPNG):

'use strict'; 

/** 
* @ngdoc: function 
* @name: portalDashboardApp.directive:ogWordCloud 
* @description: Word Cloud Generator based on the d3 word cloud generator done by Jason Davies and a simplified script by Julien Renaux 
* Directive of the portalDashboardApp 
*/ 

angular.module('portalDashboardApp') 
    .directive('ogWordCloud', function() { 
     return { 
      restrict: 'E', 
      replace: true, 
      templateUrl: './socialMedia.module/socialMedia.templates/WordCloudTemplate.html', 
      scope: { 
       words: '=' 
      }, 
      link: function (scope) { 

       var fill = d3.scale.category20b(); 

       var w = window.innerWidth - 238, 
       h = 400; 

       var max, 
       fontSize; 

       var layout = d3.layout.cloud() 
       .timeInterval(Infinity) 
       .size([w, h]) 
       .fontSize(function (d) { 
        return fontSize(+d.value); 
       }) 
       .text(function (d) { 
        return d.key; 
       }) 
       .on("end", draw); 

       var svg = d3.select("#wordCloudVisualisation").append("svg") 
       .attr("width", w) 
       .attr("height", h) 
       .attr("xmlns", 'http://www.w3.org/2000/svg') 
       .attr("xmlns:xlink", 'http://www.w3.org/1999/xlink') 
       .attr("version", '1.1') 
       .attr("id", "wordCloudSVG"); 

       var wordCloudVisualisation = svg.append("g").attr("transform", "translate(" + [w >> 1, h >> 1] + ")"); 

       update(); 

       window.onresize = function (event) { 
        update(); 
       }; 

       var tags = []; 

       scope.$watch('words', function() { 
        tags = scope.words; 
       }, true); 

       function draw(data, bounds) { 
        var w = window.innerWidth - 238, 
        h = 400; 

        svg.attr("width", w).attr("height", h); 

        var scale = bounds ? Math.min(
        w/Math.abs(bounds[1].x - w/2), 
        w/Math.abs(bounds[0].x - w/2), 
        h/Math.abs(bounds[1].y - h/2), 
        h/Math.abs(bounds[0].y - h/2))/2 : 1; 

        var text = wordCloudVisualisation.selectAll("text") 
        .data(data, function (d) { 
         return d.text.toLowerCase(); 
        }); 
        text.transition() 
        .duration(1000) 
        .attr("transform", function (d) { 
         return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; 
        }) 
        .style("font-size", function (d) { 
         return d.size + "px"; 
        }); 
        text.enter().append("text") 
        .attr("text-anchor", "middle") 
        .attr("transform", function (d) { 
         return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; 
        }) 
        .style("font-size", function (d) { 
         return d.size + "px"; 
        }) 
        .style("opacity", 1e-6) 
        .transition() 
        .duration(1000) 
        .style("opacity", 1); 
        text.style("font-family", function (d) { 
         return d.font; 
        }) 
        .style("fill", function (d) { 
         return fill(d.text.toLowerCase()); 
        }) 
        .text(function (d) { 
         return d.text; 
        }); 

        wordCloudVisualisation.transition().attr("transform", "translate(" + [w >> 1, h >> 1] + ")scale(" + scale + ")"); 
       } 

       function update() { 
        layout.font('impact').spiral('archimedean'); 
        fontSize = d3.scale['sqrt']().range([10, 100]); 
        if (scope.words.length) { 
         fontSize.domain([+scope.words[scope.words.length - 1].value || 1, +scope.words[0].value]); 
        } 
        layout.stop().words(scope.words).start(); 
       } 

////////////////////////////////////////////////////////////////// 

       scope.exportToPNG = function() { 

        var html = d3.select("svg") //svg 
         .attr("version", 1.1) 
         .attr("xmlns", "http://www.w3.org/2000/svg") 
         .node().parentNode.innerHTML; 

        var imgsrc = 'data:image/svg+xml;base64,' + btoa(html); 
        var img = '<img src="' + imgsrc + '">'; 
        d3.select("#svgdataurl").html(img); 


        var canvas = document.querySelector("canvas"), 
         context = canvas.getContext("2d"); 

        var image = new Image; 
        image.src = imgsrc; 
        image.onload = function() { 
         context.drawImage(image, 0, 0); 

         var canvasdata = canvas.toDataURL("image/png"); 

         var pngimg = '<img src="' + canvasdata + '">'; 
         d3.select("#pngdataurl").html(pngimg); 

         var a = document.createElement("a"); 
         a.download = "sample.png"; 
         a.href = canvasdata; 
         a.click(); 
        }; 
       } 
      } 
     }; 
    }); 

這是我的指令模板:

<div id="wordCloud"> 
    <button class="basicButton" ng-click="exportToPNG()">Export to .PNG</button> 
    <div id="wordCloudVisualisation"></div> 
    <canvas id="canvas"></canvas> 
    <h2>svgdataurl</h2> 
    <div id="svgdataurl"></div> 
    <h2>pngdataurl</h2> 
    <div id="pngdataurl"></div> 
</div> 

編輯:原因是,代碼會生成一張破損的圖像(例如,在佔位符中丟失圖像 時一個網站)在Chrome中。在IE中,它會在我的「svgdataurl」中創建一個圖像 ,但會彈出。我相信它不是與IE兼容的 。

我將不勝感激所有幫助!

回答

2

我能夠解決解決我的問題,這要歸功於以下職位:

Save inline SVG as JPEG/PNG/SVG

https://gist.github.com/gustavohenke/9073132

這裏是我完整的工作方案:

我的角度指令:

'use strict'; 

/** 
* @ngdoc: function 
* @name: portalDashboardApp.directive:ogWordCloud 
* @description: Word Cloud Generator based on the d3 word cloud generator done by Jason Davies and a simplified script by Julien Renaux 
* Directive of the portalDashboardApp 
*/ 

angular.module('portalDashboardApp') 
    .directive('ogWordCloud', function() { 
     return { 
      restrict: 'E', 
      replace: true, 
      templateUrl: './socialMedia.module/socialMedia.templates/WordCloudTemplate.html', 
      scope: { 
       words: '=' 
      }, 
      link: function (scope) { 

       var fill = d3.scale.category20b(); 

       var w = window.innerWidth - 238, 
       h = 400; 

       var max, 
       fontSize; 

       var layout = d3.layout.cloud() 
       .timeInterval(Infinity) 
       .size([w, h]) 
       .fontSize(function (d) { 
        return fontSize(+d.value); 
       }) 
       .text(function (d) { 
        return d.key; 
       }) 
       .on("end", draw); 

       var svg = d3.select("#wordCloudVisualisation").append("svg") 
       .attr("width", w) 
       .attr("height", h) 
       .attr("xmlns", 'http://www.w3.org/2000/svg') 
       .attr("xmlns:xlink", 'http://www.w3.org/1999/xlink') 
       .attr("version", '1.1') 
       .attr("id", "wordCloudSVG"); 

       var wordCloudVisualisation = svg.append("g").attr("transform", "translate(" + [w >> 1, h >> 1] + ")"); 

       update(); 

       window.onresize = function (event) { 
        update(); 
       }; 

       var tags = []; 

       scope.$watch('words', function() { 
        tags = scope.words; 
       }, true); 

       function draw(data, bounds) { 
        var w = window.innerWidth - 238, 
        h = 400; 

        svg.attr("width", w).attr("height", h); 

        var scale = bounds ? Math.min(
        w/Math.abs(bounds[1].x - w/2), 
        w/Math.abs(bounds[0].x - w/2), 
        h/Math.abs(bounds[1].y - h/2), 
        h/Math.abs(bounds[0].y - h/2))/2 : 1; 

        var text = wordCloudVisualisation.selectAll("text") 
        .data(data, function (d) { 
         return d.text.toLowerCase(); 
        }); 
        text.transition() 
        .duration(1000) 
        .attr("transform", function (d) { 
         return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; 
        }) 
        .style("font-size", function (d) { 
         return d.size + "px"; 
        }); 
        text.enter().append("text") 
        .attr("text-anchor", "middle") 
        .attr("transform", function (d) { 
         return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; 
        }) 
        .style("font-size", function (d) { 
         return d.size + "px"; 
        }) 
        .style("opacity", 1e-6) 
        .transition() 
        .duration(1000) 
        .style("opacity", 1); 
        text.style("font-family", function (d) { 
         return d.font; 
        }) 
        .style("fill", function (d) { 
         return fill(d.text.toLowerCase()); 
        }) 
        .text(function (d) { 
         return d.text; 
        }); 

        wordCloudVisualisation.transition().attr("transform", "translate(" + [w >> 1, h >> 1] + ")scale(" + scale + ")"); 
       } 

       function update() { 
        layout.font('impact').spiral('archimedean'); 
        fontSize = d3.scale['sqrt']().range([10, 100]); 
        if (scope.words.length) { 
         fontSize.domain([+scope.words[scope.words.length - 1].value || 1, +scope.words[0].value]); 
        } 
        layout.stop().words(scope.words).start(); 
       } 

       scope.exportToPNG2 = function() { 

        var svg = document.querySelector('#wordCloudSVG'); //svg 
        var canvas = document.createElement("canvas"); 

        var svgSize = svg.getBoundingClientRect(); 
        canvas.width = svgSize.width; 
        canvas.height = svgSize.height; 

        var ctx = canvas.getContext('2d'); 
        var data = new XMLSerializer().serializeToString(svg); 

        var DOMURL = window.URL || window.webkitURL || window; 

        var img = new Image(); 
        var svgBlob = new Blob([data], { type: 'image/svg+xml;charset=utf-8' }); 
        var url = DOMURL.createObjectURL(svgBlob); 

        img.onload = function() { 
         ctx.drawImage(img, 0, 0); 
         DOMURL.revokeObjectURL(url); 

         var imgURI = canvas 
          .toDataURL('image/png') 
          .replace('image/png', 'image/octet-stream'); 

         triggerDownload(imgURI); 
        }; 

        img.src = url; 
       } 

       function triggerDownload(imgURI) { 
        var evt = new MouseEvent('click', { 
         view: window, 
         bubbles: false, 
         cancelable: true 
        }); 

        var a = document.createElement('a'); 
        a.setAttribute('download', 'MY_COOL_IMAGE.png'); 
        a.setAttribute('href', imgURI); 
        a.setAttribute('target', '_blank'); 

        a.dispatchEvent(evt); 
       } 

      } 
     }; 
    }); 

我的指令模板:

<div id="wordCloud"> 
    <button class="basicButton" ng-click="exportToPNG2()">Export to .PNG</button> 
    <div id="wordCloudVisualisation"></div> 
    <canvas id="WordCloudCanvas"></canvas> 
</div> 

我希望這可以幫助別人!

0

您的指令之外是否已存在div #svgdataurl#pngdataurl?如果沒有,你應該把它們包含在你的指令模板中。在您所關注的示例中,它們已經出現在頁面上,而不是由click函數創建的。

你也可以看看Mike Bostock剛剛發佈的類似工具,它使用canvas.toBlob()https://github.com/mbostock/svjimmy/blob/master/index.js

+0

謝謝你的迴應!我很感激幫助。你會看到我的指令模板實際上是我的指令的一部分。我沒有外部模板文件。'模板:「

<帆布ID =‘畫布’>
」'你能給我aome對失蹤標籤的添加建議? – onmyway

+0

我爲我的指令創建了一個外部模板。請參閱更新的問題。 – onmyway