Skip to content

Commit

Permalink
Add shared chart client
Browse files Browse the repository at this point in the history
  • Loading branch information
guerler committed Feb 11, 2018
1 parent 9b6b757 commit 6ec649c
Show file tree
Hide file tree
Showing 10 changed files with 1,017 additions and 0 deletions.
7 changes: 7 additions & 0 deletions client/galaxy/scripts/apps/chart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import ChartClient from "mvc/visualization/chart/chart-client";
export const bundleEntries = {
chart: function chartEntry(options) {
return new ChartClient.View(options);
}
};
window.bundleEntries = bundleEntries;
71 changes: 71 additions & 0 deletions client/galaxy/scripts/mvc/visualization/chart/chart-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import Modal from "mvc/ui/ui-modal";
import Portlet from "mvc/ui/ui-portlet";
import Ui from "mvc/ui/ui-misc";
import Utils from "utils/utils";
import Chart from "mvc/visualization/chart/components/model";
import Deferred from "utils/deferred";
import Viewer from "mvc/visualization/chart/views/viewer";
import Editor from "mvc/visualization/chart/views/editor";
var View = Backbone.View.extend({
initialize: function(options) {
this.options = options;
this.modal = (parent.Galaxy && parent.Galaxy.modal) || new Modal.View();
this.setElement("<div/>")
$.ajax({
url: `${Galaxy.root}api/visualizations/${options.id}`
})
.done(visualization => {
window.console.log(visualization);
this.visualization = visualization;
this.chart = new Chart({}, visualization.latest_revision.config.chart_dict);
this.deferred = new Deferred();
this.viewer = new Viewer(this);
this.editor = new Editor(this);
this.$el.append(this.viewer.$el);
this.$el.append(this.editor.$el);
this.render();

})
.fail(response => {
let message = response.responseJSON && response.responseJSON.err_msg;
this.errormessage = message || "Import failed for unkown reason.";
});
},

/** Build client ui */
render: function() {
let plugin_path = this.visualization.plugin.static_url + '/' + this.visualization.type;
//import Plugin from plugin_path;
/*this.go(this.chart.load() ? "viewer" : "editor");
require(["repository/build/" + chart.get("type")], function(ChartView) {
new ChartView({ process: process, chart: chart, dataset: self.app.dataset, targets: self.targets });
}, function(err) {
chart.state(
"failed",
"Please verify that your internet connection works properly. This visualization could not be accessed in the repository. Please contact the Galaxy Team if this error persists."
);
console.debug(err);
process.resolve();
});
*/
},

/** Loads a view and makes sure that all others are hidden */
go: function(view_id) {
$(".tooltip").hide();
this.viewer.hide();
this.editor.hide();
this[view_id].show();
},

/** Split chart type into path components */
split: function(chart_type) {
var path = chart_type.split(/_(.+)/);
if (path.length >= 2) {
return path[0] + "/" + path[1];
} else {
return chart_type;
}
}
});
export default { View: View }
101 changes: 101 additions & 0 deletions client/galaxy/scripts/mvc/visualization/chart/components/model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
define(["utils/utils", "mvc/visualization/visualization-model"], function(Utils) {
return Backbone.Model.extend({
defaults: {
title: "",
type: "",
date: null,
state: "",
state_info: "",
modified: false,
dataset_id: "",
dataset_id_job: ""
},

initialize: function(options, viz_options) {
this.groups = new Backbone.Collection();
this.settings = new Backbone.Model();
this.definition = {};
this.viz_options = viz_options;
console.debug("model::initialize() - Initialized with configuration:");
console.debug(viz_options);
},

reset: function() {
this.clear().set({
title: "New Chart",
type: "__first",
dataset_id: this.viz_options.dataset_id
});
this.settings.clear();
this.groups.reset();
this.groups.add({ id: Utils.uid() });
},

state: function(value, info) {
this.set({ state: value, state_info: info });
this.trigger("set:state");
console.debug("model::state() - " + info + " (" + value + ")");
},

/** Pack and save nested chart model */
save: function(options) {
var self = this;
options = options || {};
var chart_dict = {
attributes: this.attributes,
settings: this.settings.attributes,
groups: []
};
this.groups.each(function(group) {
chart_dict.groups.push(group.attributes);
});
var viz = new Visualization({
id: this.viz_options.visualization_id || undefined,
type: "charts",
title: this.get("title") || "",
config: {
dataset_id: this.viz_options.dataset_id,
chart_dict: (this.viz_options.chart_dict = chart_dict)
}
});
viz
.save()
.then(function(response) {
if (response && response.id) {
self.viz_options.visualization_id = response.id;
options.success && options.success();
console.debug("model::save() - Received visualization id: " + response.id);
} else {
options.error && options.error();
console.debug("model::save() - Unrecognized response. Saving may have failed.");
}
})
.fail(function(response) {
options.error && options.error();
console.debug("model::save() - Saving failed.");
});
console.debug("model::save() - Saved with configuration:");
console.debug(this.viz_options);
},

/** Load nested models/collections from packed dictionary */
load: function() {
console.debug("model::load() - Attempting to load with configuration:");
console.debug(this.viz_options);
var chart_dict = this.viz_options.chart_dict;
if (chart_dict && chart_dict.attributes) {
this.set(chart_dict.attributes);
this.state("ok", "Loading saved visualization...");
this.settings.set(chart_dict.settings);
this.groups.reset();
this.groups.add(chart_dict.groups);
this.set("modified", false);
console.debug("model::load() - Loading chart model " + chart_dict.attributes.type + ".");
this.trigger("redraw");
return true;
}
console.debug("model::load() - Visualization attributes unavailable.");
return false;
}
});
});
188 changes: 188 additions & 0 deletions client/galaxy/scripts/mvc/visualization/chart/components/screenshot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/** This class enables users to export/download a chart as PNG, SVG or PDF. */
define(["libs/underscore"], function(_) {
/** PNG export */
function createPNG(options) {
if (options.$el.find("svg").length > 0) {
_svg2png(options);
} else {
_canvas2png(options.$el.find(".charts-viewport-canvas"));
}
}

/** Convert canvas to png */
function _canvas2png($canvas) {
try {
if ($canvas.width() !== 0 && $canvas.height() !== 0) {
var newCanvas = document.createElement("canvas");
newCanvas.width = $canvas.outerWidth(true);
newCanvas.height = $canvas.outerHeight(true);
var newContext = newCanvas.getContext("2d");
newContext.save();
newContext.fillStyle = "rgb(255,255,255)";
newContext.fillRect(0, 0, newCanvas.width, newCanvas.height);
newContext.restore();
newContext.translate(0, 0);
newContext.textAlign = "left";
newContext.textBaseline = "top";
function _toImage($el, x_offset, y_offset) {
var tagname = $el.prop("tagName").toLowerCase();
var p = $el.position();
var left =
x_offset +
p.left +
parseInt($el.css("marginLeft"), 10) +
parseInt($el.css("borderLeftWidth"), 10) +
parseInt($el.css("paddingLeft"), 10);
var top =
y_offset +
p.top +
parseInt($el.css("marginTop"), 10) +
parseInt($el.css("borderTopWidth"), 10) +
parseInt($el.css("paddingTop"), 10);
var w = newCanvas.width;
if (tagname == "div" || tagname == "span") {
$el.children().each(function() {
_toImage($(this), left, top);
});
} else if (tagname == "canvas") {
newContext.drawImage($el[0], left, top);
}
}
$canvas.children().each(function() {
_toImage($(this), 0, 0);
});
var imgData = newCanvas.toDataURL("image/png");
if (imgData) {
window.location.href = imgData.replace("image/png", "image/octet-stream");
}
}
} catch (err) {
console.debug("FAILED - screenshot::_canvas2png() - " + err);
if (options.error) {
options.error("Please reduce your visualization to a single panel and try again.");
}
}
}

/** Convert svg to png */
function _svg2png(options) {
var scale = 5;
var xml = toXML(options);
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var source = new Image();
var $container = $('<div style="display:none;"/>').append($(canvas));
$("body").append($container);
canvas.width = xml.width * scale;
canvas.height = xml.height * scale;
source.src = "data:image/svg+xml;base64," + btoa(xml.string);
source.onload = function() {
context.drawImage(source, 0, 0, canvas.width, canvas.height);
window.location.href = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
$container.remove();
};
}

/** SVG export */
function createSVG(options) {
window.location.href = "data:none/none;base64," + btoa(toXML(options).string);
}

/** PDF export */
function createPDF(options) {
var xml = toXML(options);
var data = {
filename: "visualization",
type: "application/pdf",
height: xml.height,
width: xml.width,
scale: 2,
svg: xml.string
};
var $el = $("body");
var form = $el.find("#viewport-form");
if (form.length === 0) {
form = $("<form>", {
id: "viewport-form",
method: "post",
action: "http://export.highcharts.com/",
display: "none"
});
$el.append(form);
}
form.empty();
for (var name in data) {
var input = $("<input/>", {
type: "hidden",
name: name,
value: data[name]
});
form.append(input);
}
try {
form.submit();
} catch (err) {
console.log(err);
}
}

/** XML export */
function toXML(options) {
var $svg = options.$el.find("svg");
if ($svg.length == 0) {
if (options.error) {
options.error("No SVG found. This visualization type does not support SVG/PDF export.");
return;
}
}
var $el = options.$el;
var nsvgs = $svg.length;
var height = parseInt($svg.first().css("height"));
var width = parseInt($svg.first().css("width"));
var serializer = new XMLSerializer();
var $composite = $("<svg/>").attr({
version: "1.1",
xmlns: "http://www.w3.org/2000/svg",
width: width * nsvgs,
height: height
});
var xmlString = "";
var offsetX = 0;
$svg.each(function() {
var $svg = $(this).clone();
_inline($svg);
var $g = $('<g transform="translate(' + offsetX + ', 0)">').attr("xmlns", "http://www.w3.org/2000/svg");
$g.append($svg.find("g").first());
$composite.append($g);
offsetX += width;
});
return {
string: serializer.serializeToString($composite[0]),
height: height,
width: width
};
}

/** inlines CSS code */
function _inline($target) {
for (var sheet_id in document.styleSheets) {
var sheet = document.styleSheets[sheet_id];
var rules = sheet.cssRules;
if (rules) {
for (var idx = 0, len = rules.length; idx < len; idx++) {
try {
$target.find(rules[idx].selectorText).each(function(i, elem) {
elem.style.cssText += rules[idx].style.cssText;
});
} catch (err) {}
}
}
}
}

return {
createPNG: createPNG,
createSVG: createSVG,
createPDF: createPDF
};
});

0 comments on commit 6ec649c

Please sign in to comment.