Skip to content

Commit

Permalink
#14 - Work on exporting charts. SVG part of the chart correctly expor…
Browse files Browse the repository at this point in the history
…ted. For time series, the x_axis is not exported yet.
  • Loading branch information
Nicolas Joseph committed Jul 6, 2015
1 parent 5d07abb commit 1e61e1e
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 4 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,5 @@ neo4J-cleanup-addon.iml
log-test.txt

extension/src/panel/panel.js
extension/src/vendors/metisMenu.min.js
extension/src/vendors/bootstrap.min.js
extension/src/vendors/*.min.js
*.zip
5 changes: 5 additions & 0 deletions extension/src/panel/panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
<div class="btn-group pull-right" role="group" aria-label="...">
<button id="liveDigestTime" type="button" class="btn btn-default btn-xs active">Live</button>
<button id="pauseDigestTime" type="button" class="btn btn-default btn-xs">Pause</button>
<button id="exportDigestTime" type="button" class="btn btn-default btn-xs">Export</button>
</div>
</div>
<!-- /.panel-heading -->
Expand All @@ -185,6 +186,7 @@
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-bar-chart-o fa-fw"></i> Digest time Distribution
<button id="exportDigestTimeDistribution" type="button" class="btn btn-default btn-xs">Export</button>
</div>
<!-- /.panel-heading -->
<div class="panel-body">
Expand All @@ -205,6 +207,7 @@
<div class="btn-group pull-right" role="group" aria-label="...">
<button id="liveDigestCount" type="button" class="btn btn-default btn-xs active">Live</button>
<button id="pauseDigestCount" type="button" class="btn btn-default btn-xs">Pause</button>
<button id="exportDigestCount" type="button" class="btn btn-default btn-xs">Export</button>
</div>
</div>
<!-- /.panel-heading -->
Expand All @@ -229,6 +232,7 @@
<div class="btn-group pull-right" role="group" aria-label="...">
<button id="liveWatchersCount" type="button" class="btn btn-default btn-xs active">Live</button>
<button id="pauseWatchersCount" type="button" class="btn btn-default btn-xs">Pause</button>
<button id="exportWatchersCount" type="button" class="btn btn-default btn-xs">Export</button>
</div>
</div>
<!-- /.panel-heading -->
Expand All @@ -248,6 +252,7 @@
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-bar-chart-o fa-fw"></i>Watchers average count depending on location
<button id="exportWatchersCountDistribution" type="button" class="btn btn-default btn-xs">Export</button>
</div>
<!-- /.panel-heading -->
<div class="panel-body">
Expand Down
1 change: 1 addition & 0 deletions panelApp/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Plots.setMainPlotsSettings([
dataFunction: registry.getDigestTimingPlotData,
pauseButton: '#pauseDigestTime',
liveButton: '#liveDigestTime',
exportButton: '#exportDigestTime',
live: true
},
{
Expand Down
124 changes: 122 additions & 2 deletions panelApp/panels/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ Plots.buildMainPlots = function(){

$('#' + plot.id).empty();

if (plot.eventTimelineId)
if (plot.eventTimelineId) {
$('#' + plot.eventTimelineId).empty();
if (plot.rangeSliderId)
}
if (plot.rangeSliderId) {
$('#' + plot.rangeSliderId).empty();
}


// Controls of the start en end date
Expand All @@ -86,6 +88,15 @@ Plots.buildMainPlots = function(){
});
}

// Controls for export as image
if (plot.exportButton){
$(plot.exportButton).unbind();

$(plot.exportButton).click(function(){
Plots.downloadSVG(plot.id, plot.plotName);
})
}

// Graph instantiation
plot.instance = new Rickshaw.Graph({
element: document.getElementById(plot.id),
Expand Down Expand Up @@ -174,4 +185,113 @@ Plots.clearAnnotations = function(){
$('.annotation').remove();
};


Plots.downloadSVG = function(divId, title){

var
source = getSource(document.getElementById(divId)),
url = window.URL.createObjectURL(new Blob(source.source, { "type" : "text\/xml" })),
a = document.createElement("a");

a.setAttribute("class", "svg-crowbar");
a.setAttribute("download", title + ".svg");
a.setAttribute("href", url);
a.click();

setTimeout(function() {
window.URL.revokeObjectURL(url);
}, 10);
};

function getSource(node) {

var
prefix = {
xmlns: "http://www.w3.org/2000/xmlns/",
xlink: "http://www.w3.org/1999/xlink",
svg: "http://www.w3.org/2000/svg"
},
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">',
svg = node.firstElementChild,
emptySvg = window.document.createElementNS(prefix.svg, 'svg');

window.document.body.appendChild(emptySvg);
var emptySvgDeclarationComputed = getComputedStyle(emptySvg);

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);
}

setInlineStyles(svg, emptySvgDeclarationComputed);

var source = (new XMLSerializer()).serializeToString(svg);
var rect = svg.getBoundingClientRect();

window.document.body.removeChild(emptySvg);

return {
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]
};
}

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]);
}
}

module.exports = Plots;

0 comments on commit 1e61e1e

Please sign in to comment.