mirror of https://github.com/CIRCL/lookyloo
new: downloadable tree as png
parent
f40009c54d
commit
7fdc47350f
|
@ -35,8 +35,8 @@
|
||||||
"secure.svg": "H8ni7t0d60nCJDVGuZpuxC+RBy/ipAjWT627D12HlZGg6LUmjSwPTQTUekm3UJupEP7TUkhXyq6WHc5gy7QBjg==",
|
"secure.svg": "H8ni7t0d60nCJDVGuZpuxC+RBy/ipAjWT627D12HlZGg6LUmjSwPTQTUekm3UJupEP7TUkhXyq6WHc5gy7QBjg==",
|
||||||
"stats.css": "/kY943FwWBTne4IIyf7iBROSfbGd82TeBicEXqKkRwawMVRIvM/Pk5MRa7okUyGIxaDjFQGmV/U1vy+PhN6Jbw==",
|
"stats.css": "/kY943FwWBTne4IIyf7iBROSfbGd82TeBicEXqKkRwawMVRIvM/Pk5MRa7okUyGIxaDjFQGmV/U1vy+PhN6Jbw==",
|
||||||
"stats_graph.js": "S/sMNQK1UMMLD0xQeEa7sq3ce8o6oPxwxGlyKVtaHOODjair86dbBDm7cu6pa/elMRDJT1j09jEFjWp+5GbhTw==",
|
"stats_graph.js": "S/sMNQK1UMMLD0xQeEa7sq3ce8o6oPxwxGlyKVtaHOODjair86dbBDm7cu6pa/elMRDJT1j09jEFjWp+5GbhTw==",
|
||||||
"tree.css": "AvSJOleYapo+xOCcOPGxTcKg+t1TxFkmr/VvgVJbXaeDOnYECzmJOIVNZii/eFouTh85uDSgr+WLQHq3hft6Kg==",
|
"tree.css": "xffZ5VGbH0dvaD3pJRj48PttTd29xtU45QozhHi/oJCKy8HU/NkHcGutpx9sOGMuY5tsKn8Pub6Ncsjj9f4TSg==",
|
||||||
"tree.js": "MezKYufVkOBLm/Z4ENrMhKzBNDslhXYTlDhjDDAbhHo6XqRzCnTMIgYtikQ1mxkwF5P61Tl1w0kalIPe4Sca6g==",
|
"tree.js": "26qV04hLcKiZB2Td5Oe/OZ2shdvGZv+xcO7VB1hcrvV3j7Urdvq/mMZ+OT5B8/iP0Ao7KvZKH3EzszXw55mkSA==",
|
||||||
"up.jpg": "d1ljZJ9f5JekyM6RLFFH2Ua44j6neiQBdUIXOenRTjGppQr3JaeglpQIH6BjPCJL177+TH52U3UIRNS5YAyKIg==",
|
"up.jpg": "d1ljZJ9f5JekyM6RLFFH2Ua44j6neiQBdUIXOenRTjGppQr3JaeglpQIH6BjPCJL177+TH52U3UIRNS5YAyKIg==",
|
||||||
"up_right.jpg": "OMmz+n+MxR34P8/fn5t4DkqKqdJRzQbXQ7fAi2lhkZIJGhVs2vIyY1f2hpYoBxDAX1OcYsSE2lqIR2vXNDGZsA==",
|
"up_right.jpg": "OMmz+n+MxR34P8/fn5t4DkqKqdJRzQbXQ7fAi2lhkZIJGhVs2vIyY1f2hpYoBxDAX1OcYsSE2lqIR2vXNDGZsA==",
|
||||||
"video.png": "gJtmkfr8I1Kw43pYEKjg6CAjgmhl1vIBKBQ3ZkxCu3wvxQm+6kf93iLrrFiY2WuiXzxEn2Leu52GJzmVN5id0g==",
|
"video.png": "gJtmkfr8I1Kw43pYEKjg6CAjgmhl1vIBKBQ3ZkxCu3wvxQm+6kf93iLrrFiY2WuiXzxEn2Leu52GJzmVN5id0g==",
|
||||||
|
|
|
@ -8,12 +8,6 @@
|
||||||
font: 12px sans-serif;
|
font: 12px sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
|
||||||
fill: none;
|
|
||||||
stroke: #ccc;
|
|
||||||
stroke-width: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flashed-messages {
|
.flashed-messages {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 5px;
|
bottom: 5px;
|
||||||
|
|
|
@ -824,7 +824,10 @@ function update(root, computed_node_width=0) {
|
||||||
// Enter any new links at the parent's previous position.
|
// Enter any new links at the parent's previous position.
|
||||||
.insert('path', "g")
|
.insert('path', "g")
|
||||||
.attr("class", "link")
|
.attr("class", "link")
|
||||||
.attr('d', diagonal),
|
.attr('d', diagonal)
|
||||||
|
.style('fill', 'none')
|
||||||
|
.style('stroke', '#ccc')
|
||||||
|
.style('stroke-width', '2px'),
|
||||||
update => update,
|
update => update,
|
||||||
exit => exit.call(exit => exit.attr('d', diagonal).remove())
|
exit => exit.call(exit => exit.attr('d', diagonal).remove())
|
||||||
).call(link => link.attr('d', diagonal));
|
).call(link => link.attr('d', diagonal));
|
||||||
|
@ -833,3 +836,57 @@ function update(root, computed_node_width=0) {
|
||||||
update(root, node_width)
|
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);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -867,6 +867,9 @@
|
||||||
</br>
|
</br>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="#" onclick="downloadSvg()" role="button">Download tree</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('image', tree_uuid=tree_uuid) }}" role="button">Download screenshot</a>
|
<a href="{{ url_for('image', tree_uuid=tree_uuid) }}" role="button">Download screenshot</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue