Skip to content

Commit

Permalink
png image export feature added, various technical fixes and improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitaeverywhere committed Apr 28, 2015
1 parent 5e347b2 commit 6234d8e
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 5 deletions.
3 changes: 2 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ gulp.task("clean", function () {
gulp.task("gatherLibs", ["clean"], function () {
return gulp.src([
"web/jsLib/joint.js",
"web/jsLib/joint.shapes.uml.js"
"web/jsLib/joint.shapes.uml.js",
"web/jsLib/ImageExporter.js"
])
.pipe(uglify({
output: {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "CacheUMLExplorer",
"version": "0.4.0",
"version": "0.5.0",
"description": "An UML Class explorer for InterSystems Caché",
"directories": {
"test": "test"
Expand Down
23 changes: 23 additions & 0 deletions web/css/extras.css
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,29 @@
left: 5px;
}

.icon.download:before {
content: "";
border: 8px solid transparent;
border-right-width: 0;
border-left-color: #fff;
left: 8px;
right: auto;
position: absolute;
top: 16px;
transform: translateY(-50%) rotate(90deg);
}

.icon.download:after {
content: "";
background-color: #fff;
width: 6px;
height: 10px;
border-radius: 1px;
position: absolute;
top: 5px;
left: 9px;
}

.icon.scaleNormal:after {
content: "1:1";
position: absolute;
Expand Down
9 changes: 8 additions & 1 deletion web/css/interface.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,20 @@ html, body {
font-size: 18pt;
}

.ui-toolBar {
.ui-rightBottomToolBar {
position: absolute;
bottom: 0;
right: 0;
padding: .5em;
}

.ui-leftBottomToolBar {
position: absolute;
bottom: 0;
left: 0;
padding: .5em;
}

#className {
text-shadow: 1px 1px 0 white, -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white;
}
11 changes: 10 additions & 1 deletion web/css/treeView.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
cursor: pointer;
border-radius: 5px;
-webkit-transition: all .2s ease;
user-select: none;
-moz-transition: all .2s ease;
-o-transition: all .2s ease;
transition: all .2s ease;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}

.tv-class-name:hover, .tv-package-name:hover {
Expand Down Expand Up @@ -54,6 +57,9 @@
border: 1px solid gray;
border-radius: 2px 2px 0 2px;
-webkit-transition: all .2s ease;
-moz-transition: all .2s ease;
-o-transition: all .2s ease;
transition: all .2s ease;
}

.tv-package-name:after {
Expand All @@ -69,6 +75,9 @@
border: 1px solid gray;
border-radius: 0 2px 2px 2px;
-webkit-transition: all .2s ease;
-moz-transition: all .2s ease;
-o-transition: all .2s ease;
transition: all .2s ease;
}

.tv-package-name:hover:before {
Expand Down
7 changes: 6 additions & 1 deletion web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<script type="text/javascript" src="jsLib/joint.js"></script>
<script type="text/javascript" src="jsLib/joint.shapes.uml.js"></script>
<script type="text/javascript" src="jsLib/joint.layout.DirectedGraph.min.js"></script>
<script type="text/javascript" src="jsLib/ImageExporter.js"></script>
<script type="text/javascript" src="js/ClassView.js"></script>
<script type="text/javascript" src="js/Lib.js"></script>
<script type="text/javascript" src="js/CacheUMLExplorer.js"></script>
Expand All @@ -32,7 +33,10 @@
<div class="ui-ClassInfo">
<span id="className"></span>
</div>
<div class="ui-toolBar">
<div class="ui-leftBottomToolBar">
<div id="button.downloadSVG" class="icon download"></div>
</div>
<div class="ui-rightBottomToolBar">
<div id="button.zoomIn" class="icon plus"></div>
<div id="button.zoomNormal" class="icon scaleNormal"></div>
<div id="button.zoomOut" class="icon minus"></div>
Expand All @@ -42,5 +46,6 @@
</div>
</div>
</div>
<canvas id="canvas" width="1000px" height="600px"></canvas>
</body>
</html>
2 changes: 2 additions & 0 deletions web/js/CacheUMLExplorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ CacheUMLExplorer.prototype.init = function () {
}
}

enableSVGDownload(this.classTree);

};
146 changes: 146 additions & 0 deletions web/jsLib/ImageExporter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* @see https://github.com/NYTimes/svg-crowbar - A bit of used code from here, thanks to it's author.
*/
var enableSVGDownload = function (classView) {

var 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">';

window.URL = (window.URL || window.webkitURL);

var prefix = {
xmlns: "http://www.w3.org/2000/xmlns/",
xlink: "http://www.w3.org/1999/xlink",
svg: "http://www.w3.org/2000/svg"
};

function getSources(doc, emptySvgDeclarationComputed) {

var svgInfo = [],
svgs = doc.querySelectorAll("svg");

[].forEach.call(svgs, function (svg) {

var par = svg.parentNode;
svg = svg.cloneNode(true);
par.appendChild(svg);
var gGroup = svg.childNodes[0];

svg.setAttribute("version", "1.1");

// removing attributes so they aren't doubled up
svg.removeAttribute("xmlns");
svg.removeAttribute("xlink");

// These are needed for the svg
if (!svg.hasAttributeNS(prefix.xmlns, "xmlns")) {
svg.setAttributeNS(prefix.xmlns, "xmlns", prefix.svg);
}

if (!svg.hasAttributeNS(prefix.xmlns, "xmlns:xlink")) {
svg.setAttributeNS(prefix.xmlns, "xmlns:xlink", prefix.xlink);
}

svg.setAttribute("width", gGroup.getBBox().width);
svg.setAttribute("height", gGroup.getBBox().height);
gGroup.setAttribute("transform", "");

setInlineStyles(svg, emptySvgDeclarationComputed);

var source = (new XMLSerializer()).serializeToString(svg);
var rect = svg.getBoundingClientRect();
svgInfo.push({
top: rect.top,
left: rect.left,
width: rect.width,
height: rect.height,
class: svg.getAttribute("class"),
id: svg.getAttribute("id"),
childElementCount: svg.childElementCount,
source: [doctype + source]
});

par.removeChild(svg);

});
return svgInfo;
}

document.getElementById("button.downloadSVG").addEventListener("click", function () {

var emptySvg = window.document.createElementNS(prefix.svg, 'svg'),
emptySvgDeclarationComputed = getComputedStyle(emptySvg),
source = getSources(document, emptySvgDeclarationComputed)[0];

var filename = (classView || {}).SELECTED_CLASS_NAME || "classDiagram";

var img = new Image();
var url = window.URL.createObjectURL(new Blob(source.source, { "type" : 'image/svg+xml;charset=utf-8'/*"text\/xml"*/ }));

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.setAttribute("width", source.width);
canvas.setAttribute("height", source.height);
document.body.appendChild(canvas);

img.onload = function () {
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/png");
var a = document.createElement("a");
a.setAttribute("download", filename + ".png");
a.setAttribute("href", dataURL/*url*/);
document.body.appendChild(a);
a.click();
setTimeout(function () {
a.parentNode.removeChild(a);
canvas.parentNode.removeChild(canvas);
window.URL.revokeObjectURL(url);
}, 10);
};

img.src = url;

});

function setInlineStyles(svg, emptySvgDeclarationComputed) {

function explicitlySetStyle (element) {
var cSSStyleDeclarationComputed = getComputedStyle(element);
var i, len, key, value;
var computedStyleStr = "";
for (i=0, len=cSSStyleDeclarationComputed.length; i<len; i++) {
key=cSSStyleDeclarationComputed[i];
value=cSSStyleDeclarationComputed.getPropertyValue(key);
if (value!==emptySvgDeclarationComputed.getPropertyValue(key)) {
computedStyleStr+=key+":"+value+";";
}
}
element.setAttribute('style', computedStyleStr);
}
function traverse(obj){
var tree = [];
tree.push(obj);
visit(obj);
function visit(node) {
if (node && node.hasChildNodes()) {
var child = node.firstChild;
while (child) {
if (child.nodeType === 1 && child.nodeName != 'SCRIPT'){
tree.push(child);
visit(child);
}
child = child.nextSibling;
}
}
}
return tree;
}
// hardcode computed css styles inside svg
var allElements = traverse(svg);
var i = allElements.length;
while (i--){
explicitlySetStyle(allElements[i]);
}
}


};

0 comments on commit 6234d8e

Please sign in to comment.