-
Notifications
You must be signed in to change notification settings - Fork 967
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
1,017 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
71
client/galaxy/scripts/mvc/visualization/chart/chart-client.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
101
client/galaxy/scripts/mvc/visualization/chart/components/model.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
188
client/galaxy/scripts/mvc/visualization/chart/components/screenshot.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
}; | ||
}); |
Oops, something went wrong.