Files
weave-scope/client/app/scripts/utils/file-utils.js
Filip Barl 69fd397217 Initial version of the resource view (#2296)
* Added resource view selector button

* Showing resource boxes in the resource view

* Crude CPU resource view prototype

* Improved the viewMode state logic

* Extracted zooming into a separate wrapper component

* Split the layout selectors between graph-view and resource-view

* Proper zooming logic for the resource view

* Moved all node networks utils to selectors

* Improved the zoom caching logic

* Further refactoring of selectors

* Added sticky labels to the resource boxes

* Added panning translation limits in the resource view

* Renamed GridModeSelector -> ViewModeSelector

* Polished the topology resource view selection logic

* Search bar hidden in the resource view

* Added per-layer topology names to the resource view

* Made metric selectors work for the resource view

* Adjusted the viewport selectors

* Renamed viewport selector to canvas (+ maximal zoom fix)

* Showing more useful metric info in the resource box labels

* Fetching only necessary nodes for the resource view

* Refactored the resource view layer component

* Addressed first batch UI comments (from the Scope meeting)

* Switch to deep zooming transform in the resource view to avoid SVG precision errors

* Renamed and moved resource view components

* Polished all the resource view components

* Changing the available metrics selection

* Improved and polished the state transition logic for the resource view

* Separated zoom limits from the zoom active state

* Renaming and bunch of comments

* Addressed all the UI comments (@davkal + @fons)

* Made graph view selectors independent from resource view selectors
2017-03-24 14:51:53 +01:00

151 lines
4.1 KiB
JavaScript

// adapted from https://github.com/NYTimes/svg-crowbar
import { each } from 'lodash';
const doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
const prefix = {
xmlns: 'http://www.w3.org/2000/xmlns/',
xlink: 'http://www.w3.org/1999/xlink',
svg: 'http://www.w3.org/2000/svg'
};
const cssSkipValues = {
auto: true,
'0px 0px': true,
visible: true,
pointer: true
};
function setInlineStyles(svg, target, emptySvgDeclarationComputed) {
function explicitlySetStyle(element, targetEl) {
const cSSStyleDeclarationComputed = getComputedStyle(element);
let computedStyleStr = '';
each(cSSStyleDeclarationComputed, (key) => {
const value = cSSStyleDeclarationComputed.getPropertyValue(key);
if (value !== emptySvgDeclarationComputed.getPropertyValue(key) && !cssSkipValues[value]) {
computedStyleStr += `${key}:${value};`;
}
});
targetEl.setAttribute('style', computedStyleStr);
targetEl.removeAttribute('data-reactid');
}
function traverse(obj) {
const tree = [];
function visit(node) {
if (node && node.hasChildNodes()) {
let child = node.firstChild;
while (child) {
if (child.nodeType === 1 && child.nodeName !== 'SCRIPT') {
tree.push(child);
visit(child);
}
child = child.nextSibling;
}
}
}
tree.push(obj);
visit(obj);
return tree;
}
// make sure logo shows up
svg.setAttribute('class', 'exported');
// hardcode computed css styles inside svg
const allElements = traverse(svg);
const allTargetElements = traverse(target);
for (let i = allElements.length - 1; i >= 0; i -= 1) {
explicitlySetStyle(allElements[i], allTargetElements[i]);
}
// set font
target.setAttribute('style', 'font-family: Arial;');
// set view box
target.setAttribute('width', svg.clientWidth);
target.setAttribute('height', svg.clientHeight);
}
function download(source, name) {
let filename = 'untitled';
if (name) {
filename = name;
} else if (window.document.title) {
filename = `${window.document.title.replace(/[^a-z0-9]/gi, '-').toLowerCase()}-${(+new Date())}`;
}
const url = window.URL.createObjectURL(new Blob(source,
{ type: 'text/xml' }
));
const a = document.createElement('a');
document.body.appendChild(a);
a.setAttribute('class', 'svg-crowbar');
a.setAttribute('download', `${filename}.svg`);
a.setAttribute('href', url);
a.style.display = 'none';
a.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
}, 10);
}
function getSVGElement() {
return document.getElementById('canvas');
}
function getSVG(doc, emptySvgDeclarationComputed) {
const svg = getSVGElement();
const target = svg.cloneNode(true);
target.setAttribute('version', '1.1');
// removing attributes so they aren't doubled up
target.removeAttribute('xmlns');
target.removeAttribute('xlink');
// These are needed for the svg
if (!target.hasAttributeNS(prefix.xmlns, 'xmlns')) {
target.setAttributeNS(prefix.xmlns, 'xmlns', prefix.svg);
}
if (!target.hasAttributeNS(prefix.xmlns, 'xmlns:xlink')) {
target.setAttributeNS(prefix.xmlns, 'xmlns:xlink', prefix.xlink);
}
setInlineStyles(svg, target, emptySvgDeclarationComputed);
const source = (new XMLSerializer()).serializeToString(target);
return [doctype + source];
}
function cleanup() {
const crowbarElements = document.querySelectorAll('.svg-crowbar');
[].forEach.call(crowbarElements, (el) => {
el.parentNode.removeChild(el);
});
// hide embedded logo
const svg = getSVGElement();
svg.setAttribute('class', '');
}
export function saveGraph(filename) {
window.URL = (window.URL || window.webkitURL);
// add empty svg element
const emptySvg = window.document.createElementNS(prefix.svg, 'svg');
window.document.body.appendChild(emptySvg);
const emptySvgDeclarationComputed = getComputedStyle(emptySvg);
const svgSource = getSVG(document, emptySvgDeclarationComputed);
download(svgSource, filename);
cleanup();
}