new: downloadable tree as png

pull/919/head
Adrian Maraj 2024-05-14 12:09:43 +02:00 committed by Raphaël Vinot
parent 4a6a00c86b
commit bef367b65c
4 changed files with 63 additions and 9 deletions

View File

@ -35,8 +35,8 @@
"secure.svg": "H8ni7t0d60nCJDVGuZpuxC+RBy/ipAjWT627D12HlZGg6LUmjSwPTQTUekm3UJupEP7TUkhXyq6WHc5gy7QBjg==",
"stats.css": "/kY943FwWBTne4IIyf7iBROSfbGd82TeBicEXqKkRwawMVRIvM/Pk5MRa7okUyGIxaDjFQGmV/U1vy+PhN6Jbw==",
"stats_graph.js": "S/sMNQK1UMMLD0xQeEa7sq3ce8o6oPxwxGlyKVtaHOODjair86dbBDm7cu6pa/elMRDJT1j09jEFjWp+5GbhTw==",
"tree.css": "AvSJOleYapo+xOCcOPGxTcKg+t1TxFkmr/VvgVJbXaeDOnYECzmJOIVNZii/eFouTh85uDSgr+WLQHq3hft6Kg==",
"tree.js": "MezKYufVkOBLm/Z4ENrMhKzBNDslhXYTlDhjDDAbhHo6XqRzCnTMIgYtikQ1mxkwF5P61Tl1w0kalIPe4Sca6g==",
"tree.css": "xffZ5VGbH0dvaD3pJRj48PttTd29xtU45QozhHi/oJCKy8HU/NkHcGutpx9sOGMuY5tsKn8Pub6Ncsjj9f4TSg==",
"tree.js": "26qV04hLcKiZB2Td5Oe/OZ2shdvGZv+xcO7VB1hcrvV3j7Urdvq/mMZ+OT5B8/iP0Ao7KvZKH3EzszXw55mkSA==",
"up.jpg": "d1ljZJ9f5JekyM6RLFFH2Ua44j6neiQBdUIXOenRTjGppQr3JaeglpQIH6BjPCJL177+TH52U3UIRNS5YAyKIg==",
"up_right.jpg": "OMmz+n+MxR34P8/fn5t4DkqKqdJRzQbXQ7fAi2lhkZIJGhVs2vIyY1f2hpYoBxDAX1OcYsSE2lqIR2vXNDGZsA==",
"video.png": "gJtmkfr8I1Kw43pYEKjg6CAjgmhl1vIBKBQ3ZkxCu3wvxQm+6kf93iLrrFiY2WuiXzxEn2Leu52GJzmVN5id0g==",

View File

@ -8,12 +8,6 @@
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
.flashed-messages {
position: fixed;
bottom: 5px;

View File

@ -824,7 +824,10 @@ function update(root, computed_node_width=0) {
// Enter any new links at the parent's previous position.
.insert('path', "g")
.attr("class", "link")
.attr('d', diagonal),
.attr('d', diagonal)
.style('fill', 'none')
.style('stroke', '#ccc')
.style('stroke-width', '2px'),
update => update,
exit => exit.call(exit => exit.attr('d', diagonal).remove())
).call(link => link.attr('d', diagonal));
@ -833,3 +836,57 @@ function update(root, computed_node_width=0) {
update(root, node_width)
}
}
//download the tree as png file
const downloadSvg = () => {
const svgElement = document.querySelector('svg');
const svgCopy = svgElement.cloneNode(true);
const images = svgCopy.querySelectorAll('image');
const promises = [];
images.forEach((imageElement) => {
const promise = new Promise((resolve, reject) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const image = new Image();
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0);
const dataURL = canvas.toDataURL("image/svg+xml");
imageElement.setAttribute('href', dataURL);
resolve();
};
image.onerror = function() {
reject(new Error('Error'));
};
image.src = imageElement.getAttribute('href');
});
promises.push(promise);
});
Promise.all(promises).then(() => {
var svgData = new XMLSerializer().serializeToString(svgCopy);
var svgBlob = new Blob([svgData], { type: "image/svg+xml;charset=utf-8" });
var url = URL.createObjectURL(svgBlob);
var img = new Image();
img.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = svgCopy.width.baseVal.value * 2;
canvas.height = svgCopy.height.baseVal.value * 2;
var ctx = canvas.getContext('2d');
ctx.fillStyle='white';
ctx.fillRect(0,0,canvas.width,canvas.height)
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
var png = canvas.toDataURL('image/png');
var a = document.createElement('a');
a.download = 'tree.png';
a.href = png;
a.click();
};
img.src = url;
}).catch((error) => {
console.error('Error:', error);
});
};

View File

@ -867,6 +867,9 @@
</br>
<div class="modal-body">
<ul>
<li>
<a href="#" onclick="downloadSvg()" role="button">Download tree</a>
</li>
<li>
<a href="{{ url_for('image', tree_uuid=tree_uuid) }}" role="button">Download screenshot</a>
</li>