简体   繁体   中英

JavaScript - Export Div with SVG chart + HTML as and Image

We have angular js application which uses highchart js library and it render chart as SVG. We have made several widget which display combination of data, let say in some widget we have only SVG chart, in some we have only tabular data rendered with angular directive, while in some widget we have combination of both ie some chart + some HTML (it can be simple bullet list or let say tabular data rendered with angular). Now we want to give functionality so that each widget can be exported as image.

We came across this example jsfiddle.net/8ypxW/3/ which use html2canvas library and work well with HTML only data, but SVG chart is not exported with this.

We thought to generate image from server side through C#, but each widget is generated with js library (highchart & angular), so in this case we do not have any direct support on server side.

What are the solution for above scenario? or what can be other approach to achieve similar.

I think dom-to-image.js is a bit more accurate than html to canvas, here are some tricks:

dom-to-image let you generate from html svg data url format, yes I know why would you do that, well it's more accurate, with that svg a image is painted inside a canvas (what you need in your case, or something more complex if you need entire page printed in an image as in my example). From that canvas you can pull the image, resize it, download it.

Copyrights: http://jsfiddle.net/gregfedorov/Qh9X5/9/ and http://jsfiddle.net/christopheviau/v6VMf/

 ///dom to svg module document.getElementById('downloadbody').onclick= function(){ var wrapper = document.getElementsByTagName("BODY")[0]; //dom to image domtoimage.toSvg(wrapper).then(function (svgDataUrl) { //download function downloadPNGFromAnyImageSrc(svgDataUrl); }); } document.getElementById('downloadcircle').onclick= function(){ var wrapper = document.getElementById('circle'); //dom to image domtoimage.toSvg(wrapper).then(function (svgDataUrl) { //download function downloadPNGFromAnyImageSrc(svgDataUrl); }); } document.getElementById('downloadtable').onclick= function(){ var wrapper = document.getElementById('table'); //dom to image domtoimage.toSvg(wrapper).then(function (svgDataUrl) { //download function downloadPNGFromAnyImageSrc(svgDataUrl); }); } function downloadPNGFromAnyImageSrc(src) { //recreate the image with src recieved var img = new Image; //when image loaded (to know width and height) img.onload = function(){ //drow image inside a canvas var canvas = convertImageToCanvas(img); //get image/png from convas var pngImage = convertCanvasToImage(canvas); //download var anchor = document.createElement('a'); anchor.setAttribute('href', pngImage.src); anchor.setAttribute('download', 'image.png'); anchor.click(); }; img.src = src; // Converts image to canvas; returns new canvas element function convertImageToCanvas(image) { var canvas = document.createElement("canvas"); canvas.width = image.width; canvas.height = image.height; canvas.getContext("2d").drawImage(image, 0, 0); return canvas; } // Converts canvas to an image function convertCanvasToImage(canvas) { var image = new Image(); image.src = canvas.toDataURL("image/png"); return image; } } ////// svg's generations ////CIrcle Modeule/////// var dataset = { apples: [53245, 28479, 19697, 24037, 40245], }; var width = 460, height = 300, radius = Math.min(width, height) / 2; var color = d3.scale.category20(); var pie = d3.layout.pie() .sort(null); var arc = d3.svg.arc() .innerRadius(radius - 100) .outerRadius(radius - 50); var svg = d3.select("#circle").append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); var path = svg.selectAll("path") .data(pie(dataset.apples)) .enter().append("path") .attr("fill", function(d, i) { return color(i); }) .attr("d", arc); // Table module //////////////////////////////////// var Table = function module() { var opts = { width: 200, height: 200, margins: {top: 20, right: 20, bottom: 20, left: 20} }; function exports(selection) { selection.each(function (dataset) { //________________________________________________ // Data //________________________________________________ var columnLabel = dataset.columnLabel; var rowLabel = dataset.rowLabel; var value = dataset.value; //________________________________________________ // DOM preparation //________________________________________________ // Size var chartW = Math.max(opts.width - opts.margins.left - opts.margins.right, 0.1); var chartH = Math.max(opts.height - opts.margins.top - opts.margins.bottom, 0.1); // SVG var parentDiv = d3.select(this).html(''); var svg = parentDiv.append('svg').attr('width', opts.width).attr('height', opts.height); var visSvg = svg.append('g').attr('class', 'vis-group').attr('transform', 'translate(' + opts.margins.left + ',' + opts.margins.top + ')'); var tableBodySvg = visSvg.append('g').attr('class', 'chart-group'); var tableHeaderSvg = visSvg.append('g').attr('class', 'chart-group'); var rowHeaderSvg = tableHeaderSvg.append('g').attr('class', 'row-header'); var colHeaderSvg = tableHeaderSvg.append('g').attr('class', 'col-header'); //________________________________________________ // Table //________________________________________________ var rowHeaderLevelNum = 1; var colHeaderLevelNum = 1; var cellH = chartH / (value.length + rowHeaderLevelNum); var cellW = chartW / (value[0].length + colHeaderLevelNum); // Row header var rowHeaderCell = rowHeaderSvg.selectAll('rect.row-header-cell') .data(rowLabel); rowHeaderCell.enter().append('rect') .attr({ class:'row-header-cell', width:cellW, height:cellH, x: 0, y: function(d, i){return i * cellH + (cellH * colHeaderLevelNum)} }) .style({fill:'#eee', stroke:'silver'}); // Row header text rowHeaderCell.enter().append('text') .attr({ class:'row-header-content', x: 0, y: function(d, i){return i * cellH + (cellH * colHeaderLevelNum)}, dx: cellW/2, dy: cellH/2 }) .style({fill:'black', 'text-anchor':'middle'}) .text(function(d, i){return d;}); // Col header var colHeaderCell = colHeaderSvg.selectAll('rect.col-header-cell') .data(columnLabel); colHeaderCell.enter().append('rect') .attr({ class:'col-header-cell', width:cellW, height:cellH, x: function(d, i){return i * cellW + (cellW * rowHeaderLevelNum)}, y: 0 }) .style({fill:'#eee', stroke:'silver'}); // Col header text colHeaderCell.enter().append('text') .attr({ class:'col-header-content', x: function(d, i){return i * cellW + (cellW * rowHeaderLevelNum)}, y: 0, dx: cellW/2, dy: cellH/2 }) .style({fill:'black', 'text-anchor':'middle'}) .text(function(d, i){return d;}); // Body var row = tableBodySvg.selectAll('g.row') .data(value); row.enter().append('g') .attr('class', 'cell row') .each(function(pD, pI){ // Cells var cell = d3.select(this) .selectAll('rect.cell') .data(pD); cell.enter().append('rect') .attr({ class:'cell', width:cellW, height:cellH, x: function(d, i){return i * cellW + (cellW * rowHeaderLevelNum)}, y: function(d, i){return pI * cellH + cellH} }) .style({fill:'white', stroke:'silver'}); // Text cell.enter().append('text') .attr({ class:'cell-content', width:cellW, height:cellH, x: function(d, i){return i * cellW + (cellW * rowHeaderLevelNum)}, y: function(d, i){return pI * cellH + cellH}, dx: cellW/2, dy: cellH/2 }) .style({fill:'black', 'text-anchor':'middle'}) .text(function(d, i){return d;}); }); }); } exports.opts = opts; createAccessors(exports, opts); return exports; }; // Helper function //////////////////////////////////// var createAccessors = function(visExport) { for (var n in visExport.opts) { if (!visExport.opts.hasOwnProperty(n)) continue; visExport[n] = (function(n) { return function(v) { return arguments.length ? (visExport.opts[n] = v, this) : visExport.opts[n]; } })(n); } }; // Usage //////////////////////////////////// var dataset = { rowLabel: ['A', 'B', 'C', 'D', 'E'], columnLabel: ['P', 'Q', 'R', 'S'], value: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19, 20]] }; var width = 400; var height = 300; var table = Table().width(width).height(height); d3.select('#table') .datum(dataset) .call(table); 
 body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; margin: auto; position: relative; width: 960px; background-color:blue; } text { font: 10px sans-serif; } form { position: absolute; right: 10px; top: 10px; } 
 <script src="https://mbostock.github.io/d3/d3.js"></script> <script src="https://rawgit.com/tsayen/dom-to-image/master/src/dom-to-image.js"></script> <div> Using dom-to-image.js transform anny given html to a image (svg - no quality loss)<br> 1. tansform html into svg<br> 2. drow svg inside hidden canvas<br> 3. export canvas jpg or png<br> 4. I you like donwload the thing<br> </div> <button id='downloadbody'>Download body</button> <button id='downloadcircle'>Download Circle</button> <button id='downloadtable'>Download Table</button> <div id="circle"> </div> <div id="table"> </div> 

phantomjs will convert html + svg to an image. It would need to run server side as a separate process, but could be called from C#.

Maybe you could try SVG2Bitmap to first convert the SVG to an image, then use html2canvas. This is the approach used in this similar question .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM