Commit 800324b3 authored by Mathieu Giraud's avatar Mathieu Giraud

Merge branch 'feature-c/3240-export-plots' into 'dev'

Export SVG to PNG

Closes #3240

See merge request !287
parents f80461d5 f5e4ead6
Pipeline #39969 passed with stages
in 5 minutes and 13 seconds
......@@ -130,8 +130,8 @@
</div>
<div class="menu_box">
<a class="buttonSelector" id="export_analysis" onclick="javascript:m.saveAnalysis()">export analysis</a>
<a class="buttonSelector" id="export_svg1" onclick="javascript:graph.resize(1400,800);m.exportSVG('visu2_svg')">export SVG graph</a>
<a class="buttonSelector" id="export_svg2" onclick="javascript:sp.resize(1400,800);sp.fastForward();m.exportSVG('visu_svg')">export SVG plot</a>
<a class="buttonSelector" id="export_svg1" onclick="javascript:m.exportViewToPNG(document.querySelector('#visu2_svg'))">export top graph (PNG)</a>
<a class="buttonSelector" id="export_svg2" onclick="javascript:m.exportViewToPNG(document.querySelector('#visu_svg'))">export bottom graph (PNG)</a>
<a class="buttonSelector" id="export_csv" onclick="javascript:m.exportCSV()">export csv (visible clones)</a>
<a class="buttonSelector" id="export_fasta" onclick="javascript:m.exportFasta()">export fasta (selected clones)</a>
</div>
......
......@@ -14,7 +14,8 @@ require(["jquery",
"tsne",
"jstree.min",
"jquery.caret",
"jquery.atwho"], function() {
"jquery.atwho",
"svgExport"], function() {
// Then config file (needed by Vidjil)
require(['../conf'], function() {
loadAfterConf()
......
......@@ -55,6 +55,11 @@ Tools
* @license MIT
* @compatibility IE 6+, Firefox 2+, Safari 3.2+, Chrome 3+, Opera 10+
svgExport.js : Export SVG to PNG
* @author Nikita Rokotyan, adapted by the Vidjil Team
* @link http://bl.ocks.org/Rokotyan/0556f8facbaf344507cdc45dc3622177
* @license MIT
tsne.js : Implementation of TSNE algorithm
* @version 2d62a1c4
* @author Andrej Karpathy
......
/*
This code is coming from
http://bl.ocks.org/Rokotyan/0556f8facbaf344507cdc45dc3622177 released under
the MIT license and has then been slightly modified to better get the CSS
rules.
This code can thus be used under the MIT license.
*/
function getSVGString( svgNode ) {
svgNode.setAttribute('xlink', 'http://www.w3.org/1999/xlink');
var cssStyleText = getCSSStyles( svgNode );
appendCSS( cssStyleText, svgNode );
var serializer = new XMLSerializer();
var svgString = serializer.serializeToString(svgNode);
svgString = svgString.replace(/(\w+)?:?xlink=/g, 'xmlns:xlink='); // Fix root xlink without namespace
svgString = svgString.replace(/NS\d+:href/g, 'xlink:href'); // Safari NS namespace fix
return svgString;
function getCSSStyles( parentElement ) {
var selectorTextArr = [];
// Add Parent element Id and Classes to the list
selectorTextArr.push( '#'+parentElement.id.toLowerCase() );
for (var c = 0; c < parentElement.classList.length; c++)
if ( !contains('.'+parentElement.classList[c], selectorTextArr) )
selectorTextArr.push( '.'+parentElement.classList[c].toLowerCase() );
// Add Children element Ids and Classes to the list
var children = $(parentElement).find('*');
var parents = $(parentElement).parents();
pushIDAndClasses(children, selectorTextArr);
pushIDAndClasses(parents, selectorTextArr);
// Extract CSS Rules
var extractedCSSText = "";
for (var i = 0; i < document.styleSheets.length; i++) {
var s = document.styleSheets[i];
try {
if(!s.cssRules) continue;
} catch( e ) {
if(e.name !== 'SecurityError') throw e; // for Firefox
continue;
}
var cssRules = s.cssRules;
for (var r = 0; r < cssRules.length; r++) {
if (typeof cssRules[r].selectorText !== 'undefined') {
var currentRule = cssRules[r].selectorText.split(/\s*,\s*/);
for (var q = 0; q < currentRule.length; q++) {
if ( contains( currentRule[q].toLowerCase(), selectorTextArr ) )
extractedCSSText += cssRules[r].cssText;
}
}
}
}
return extractedCSSText;
function contains(str,arr) {
return arr.indexOf( str ) === -1 ? false : true;
}
function pushIDAndClasses(nodes, selectorTextArr) {
for (var i = 0; i < nodes.length; i++) {
var id = nodes[i].id;
if ( !contains('#'+id, selectorTextArr) )
selectorTextArr.push( '#'+id.toLowerCase() );
var classes = nodes[i].classList;
for (var c = 0; c < classes.length; c++)
if ( !contains('.'+classes[c], selectorTextArr) )
selectorTextArr.push( '.'+classes[c].toLowerCase() );
selectorTextArr.push(nodes[i].tagName.toLowerCase());
}
}
}
function appendCSS( cssText, element ) {
var styleElement = document.createElement("style");
styleElement.setAttribute("type","text/css");
styleElement.innerHTML = cssText;
var refNode = element.hasChildNodes() ? element.children[0] : null;
element.insertBefore( styleElement, refNode );
}
}
function svgString2Image( svgString, width, height, format, name, callback ) {
var format = format ? format : 'png';
var imgsrc = 'data:image/svg+xml;base64,'+ btoa( unescape( encodeURIComponent( svgString ) ) ); // Convert SVG string to data URL
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
var image = new Image();
image.onload = function() {
context.clearRect ( 0, 0, width, height );
context.drawImage(image, 0, 0, width, height);
canvas.toBlob( function(blob) {
var filesize = Math.round( blob.length/1024 ) + ' KB';
if ( callback ) callback( blob, filesize, name );
});
};
image.src = imgsrc;
}
function saveD3ToPNG( dataBlob, filesize, filename ){
saveAs( dataBlob, filename ); // FileSaver.js function
}
function exportD3ToPNG(svgTag, filename) {
var svgString = getSVGString(svgTag);
svgString2Image( svgString, 2*svgTag.width.baseVal.value, 2*svgTag.height.baseVal.value, 'png', filename+'.png', saveD3ToPNG ); // passes Blob and filesize String to the callback
}
......@@ -2089,41 +2089,7 @@ changeAlleleNotation: function(alleleNotation) {
saveAs(textFileAsBlob, filename + ".csv");
},
/**
* save a svg file of the selected svg element.
* @return {file} svg
* */
exportSVG: function (elementID) {
var self = this;
var element = document.getElementById(elementID);
$(document).ready(function() {
$.when($.get("css/svg.css"))
.done(function(css) {
var textToWrite = '<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">';
textToWrite += "<style>";
css = css.replace(/\/\*.+?\*\/|\/\/.*(?=[\n\r])/g, '');
textToWrite += css;
textToWrite += "</style>";
textToWrite += element.innerHTML;
textToWrite += "</svg>";
var textFileAsBlob = new Blob([textToWrite], {
type: 'text'
});
var filename = self.getPrintableAnalysisName().replace(/[ \/\\:]/,'_')
saveAs(textFileAsBlob, filename + ".svg");
self.resize();
});
})
},
/**
* save a csv file of the currently visibles clones.
* @return {string} csv
......@@ -2170,6 +2136,10 @@ changeAlleleNotation: function(alleleNotation) {
}
},
exportViewToPNG: function(tag) {
exportD3ToPNG(tag, decodeURIComponent(this.getPrintableAnalysisName().replace(/[ \/\\:]/,'_')));
},
/**
* produce an html systemBox of the given system
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment