diff --git a/config/plugins/visualizations/openlayers/package.json b/config/plugins/visualizations/openlayers/package.json deleted file mode 100644 index 17f1cb6c590f..000000000000 --- a/config/plugins/visualizations/openlayers/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "visualization", - "version": "0.1.0", - "description": "Map visualization using OpenLayers", - "keywords": [ - "galaxy", - "visualization" - ], - "license": "AFL-3.0", - "dependencies": { - "axios": "^0.19.0", - "babel-preset-env": "^1.6.1", - "backbone": "^1.3.3", - "bootstrap": "^3.3.7", - "file-saver": "^2.0.2", - "jquery": "^3.3.1", - "jszip": "^3.2.2", - "jszip-utils": "^0.1.0", - "ol": "^5.3.3", - "proj4": "^2.5.0", - "shpjs": "^3.4.3", - "underscore": "^1.8.3" - }, - "scripts": { - "build": "parcel build src/script.js --dist-dir static --no-source-maps" - }, - "devDependencies": { - "buffer": "^6.0.3", - "parcel": "^2.12.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - } -} diff --git a/config/plugins/visualizations/openlayers/src/script.js b/config/plugins/visualizations/openlayers/src/script.js deleted file mode 100644 index 90922403fa7f..000000000000 --- a/config/plugins/visualizations/openlayers/src/script.js +++ /dev/null @@ -1,260 +0,0 @@ -import $ from "jquery"; -import _ from "underscore"; - -import { Map, View, Graticule } from "ol"; -import { OSM, Vector } from "ol/source"; -import { GeoJSON } from "ol/format"; -import * as interaction from "ol/interaction"; -import * as style from "ol/style"; -import * as layer from "ol/layer"; -import * as control from "ol/control"; -import { saveAs } from "file-saver"; - -import shp from "shpjs"; -import axios from "axios"; - -/* This will be part of the charts/viz standard lib in 23.1 */ -const slashCleanup = /(\/)+/g; -function prefixedDownloadUrl(root, path) { - return `${root}/${path}`.replace(slashCleanup, "/"); -} - -var MapViewer = (function(mv) { - mv.gMap = null; - - /** Set the style properties of shapes */ - mv.setStyle = selectedColor => { - const styles = { - Polygon: new style.Style({ - stroke: new style.Stroke({ - color: selectedColor, - width: 1 - }), - fill: new style.Fill({ - color: "rgba(0, 0, 255, 0.1)" - }) - }), - Circle: new style.Style({ - stroke: new style.Stroke({ - color: selectedColor, - width: 1 - }), - fill: new style.Fill({ - color: "rgba(0, 0, 255, 0.1)" - }) - }), - Point: new style.Style({ - image: new style.Circle({ - radius: 5, - fill: new style.Fill({ - color: "rgba(0, 0, 255, 0.1)" - }), - stroke: new style.Stroke({ color: selectedColor, width: 1 }) - }) - }), - LineString: new style.Style({ - stroke: new style.Stroke({ - color: selectedColor, - width: 1 - }) - }), - MultiLineString: new style.Style({ - stroke: new style.Stroke({ - color: selectedColor, - width: 1 - }) - }), - MultiPoint: new style.Style({ - image: new style.Circle({ - radius: 5, - fill: new style.Fill({ - color: "rgba(0, 0, 255, 0.1)" - }), - stroke: new style.Stroke({ color: selectedColor, width: 1 }) - }) - }), - MultiPolygon: new style.Style({ - stroke: new style.Stroke({ - color: selectedColor, - width: 1 - }), - fill: new style.Fill({ - color: "rgba(0, 0, 255, 0.1)" - }) - }), - GeometryCollection: new style.Style({ - stroke: new style.Stroke({ - color: selectedColor, - width: 1 - }), - fill: new style.Fill({ - color: selectedColor - }), - image: new style.Circle({ - radius: 10, - fill: null, - stroke: new style.Stroke({ - color: selectedColor - }) - }) - }) - }; - return styles; - }; - - /** Set up events and methods for interactions with map view*/ - mv.setInteractions = (source, options) => { - const geometryType = options.chart.settings.get("geometry_type"); - const geometryColor = options.chart.settings.get("geometry_color"); - let drawInteraction; - - const addInteraction = () => { - if (geometryType !== "None") { - drawInteraction = new interaction.Draw({ - source: source, - type: geometryType, - freehand: true - }); - drawInteraction.on("drawstart", event => { - const sty = new style.Style({ - stroke: new style.Stroke({ - color: geometryColor, - width: 2 - }), - fill: new style.Fill({ - color: "rgba(0, 0, 255, 0.1)" - }) - }); - event.feature.setStyle(sty); - }); - mv.gMap.addInteraction(drawInteraction); - } - }; - addInteraction(); - }; - - /** Export the map view to PNG image*/ - mv.exportMap = () => { - mv.gMap.once("rendercomplete", event => { - const canvas = event.context.canvas; - let fileName = Math.random() - .toString(11) - .replace("0.", ""); - fileName += ".png"; - if (navigator.msSaveBlob) { - navigator.msSaveBlob(canvas.msToBlob(), fileName); - } else { - canvas.toBlob(blob => { - saveAs(blob, fileName); - }); - } - }); - mv.gMap.renderSync(); - }; - - /** Create the map view */ - mv.setMap = (vSource, target, options, styleFunction) => { - const tile = new layer.Tile({ source: new OSM() }); - // add fullscreen handle - const fullScreen = new control.FullScreen(); - // add scale to the map - const scaleLineControl = new control.ScaleLine(); - // create vector with styles - const vectorLayer = new layer.Vector({ - source: vSource, - style: styleFunction - }); - - const view = new View({ - center: [0, 0], - zoom: 2 - }); - - // create map view - mv.gMap = new Map({ - controls: control.defaults().extend([scaleLineControl, fullScreen]), - interactions: interaction.defaults().extend([new interaction.DragRotateAndZoom()]), - layers: [tile, vectorLayer], - target: target, - loadTilesWhileInteracting: true, - view: view - }); - - // add grid lines - const graticule = new Graticule({ - strokeStyle: new style.Stroke({ - color: "rgba(255, 120, 0, 0.9)", - width: 2, - lineDash: [0.5, 4] - }), - showLabels: true - }); - - mv.gMap.addInteraction(new interaction.Modify({ source: vSource })); - mv.gMap.addControl(new control.ZoomSlider()); - graticule.setMap(mv.gMap); - mv.setInteractions(vSource, options); - }; - - /** Load the map GeoJson and Shapefiles*/ - mv.loadFile = (filePath, fileType, options, chart) => { - const target = options.target; - const formatType = new GeoJSON(); - const toExport = options.chart.settings.get("export_map"); - const geometryColor = options.chart.settings.get("geometry_color"); - const selectedStyles = mv.setStyle(geometryColor); - const styleFunction = feature => { - return selectedStyles[feature.getGeometry().getType()]; - }; - - if (toExport === "export") { - mv.exportMap(); - } - - if (fileType === "geojson") { - const sourceVec = new Vector({ format: formatType, url: filePath, wrapX: false }); - mv.createMap(filePath, sourceVec, options, chart, styleFunction, target); - } else if (fileType === "shp") { - axios.get(filePath, { responseType: "arraybuffer" }).then(shpfile => { - console.debug(shpfile); - shp(shpfile.data).then( - geojson => { - const url = window.URL.createObjectURL( - new Blob([JSON.stringify(geojson)], { type: "application/json" }) - ); - const sourceVec = new Vector({ format: formatType, url: url, wrapX: false }); - mv.createMap(url, sourceVec, options, chart, styleFunction, target); - }, - failure => { - console.debug("FAILURE!", failure); - } - ); - }); - } - }; - - mv.createMap = (filePath, sourceVec, options, chart, styleFunction, target) => { - mv.setMap(sourceVec, target, options, styleFunction); - chart.state("ok", "Chart drawn."); - options.process.resolve(); - }; - - return mv; -})(MapViewer || {}); - -window.bundleEntries = window.bundleEntries || {}; -window.bundleEntries.load = function (options) { - const chart = options.chart; - const dataset = options.dataset; - const downloadUrl = prefixedDownloadUrl(options.root, dataset.download_url); - $.ajax({ - url: downloadUrl, - success: () => { - MapViewer.loadFile(downloadUrl, dataset.extension, options, chart); - }, - error: () => { - chart.state("failed", "Failed to access dataset."); - options.process.resolve(); - } - }); -} diff --git a/config/plugins/visualizations/openlayers/static/logo.png b/config/plugins/visualizations/openlayers/static/logo.png deleted file mode 100644 index 29a440ff2bdb..000000000000 Binary files a/config/plugins/visualizations/openlayers/static/logo.png and /dev/null differ diff --git a/config/plugins/visualizations/openlayers/static/logo.svg b/config/plugins/visualizations/openlayers/static/logo.svg new file mode 100644 index 000000000000..6295e16b8a35 --- /dev/null +++ b/config/plugins/visualizations/openlayers/static/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/config/plugins/visualizations/openlayers/static/ol.css b/config/plugins/visualizations/openlayers/static/ol.css deleted file mode 100644 index 79d87d00a509..000000000000 --- a/config/plugins/visualizations/openlayers/static/ol.css +++ /dev/null @@ -1,251 +0,0 @@ -.ol-box { - box-sizing: border-box; - border-radius: 2px; - border: 2px solid blue; -} - -.ol-mouse-position { - top: 8px; - right: 8px; - position: absolute; -} - -.ol-scale-line { - background: rgba(0,60,136,0.3); - border-radius: 4px; - bottom: 8px; - left: 8px; - padding: 2px; - position: absolute; -} -.ol-scale-line-inner { - border: 1px solid #eee; - border-top: none; - color: #eee; - font-size: 10px; - text-align: center; - margin: 1px; - will-change: contents, width; -} -.ol-overlay-container { - will-change: left,right,top,bottom; -} - -.ol-unsupported { - display: none; -} -.ol-viewport, .ol-unselectable { - -webkit-touch-callout: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-tap-highlight-color: rgba(0,0,0,0); -} -.ol-selectable { - -webkit-touch-callout: default; - -webkit-user-select: text; - -moz-user-select: text; - -ms-user-select: text; - user-select: text; -} -.ol-grabbing { - cursor: -webkit-grabbing; - cursor: -moz-grabbing; - cursor: grabbing; -} -.ol-grab { - cursor: move; - cursor: -webkit-grab; - cursor: -moz-grab; - cursor: grab; -} -.ol-control { - position: absolute; - background-color: rgba(255,255,255,0.4); - border-radius: 4px; - padding: 2px; -} -.ol-control:hover { - background-color: rgba(255,255,255,0.6); -} -.ol-zoom { - top: .5em; - left: .5em; -} -.ol-rotate { - top: .5em; - right: .5em; - transition: opacity .25s linear, visibility 0s linear; -} -.ol-rotate.ol-hidden { - opacity: 0; - visibility: hidden; - transition: opacity .25s linear, visibility 0s linear .25s; -} -.ol-zoom-extent { - top: 4.643em; - left: .5em; -} -.ol-full-screen { - right: .5em; - top: .5em; -} -@media print { - .ol-control { - display: none; - } -} - -.ol-control button { - display: block; - margin: 1px; - padding: 0; - color: white; - font-size: 1.14em; - font-weight: bold; - text-decoration: none; - text-align: center; - height: 1.375em; - width: 1.375em; - line-height: .4em; - background-color: rgba(0,60,136,0.5); - border: none; - border-radius: 2px; -} -.ol-control button::-moz-focus-inner { - border: none; - padding: 0; -} -.ol-zoom-extent button { - line-height: 1.4em; -} -.ol-compass { - display: block; - font-weight: normal; - font-size: 1.2em; - will-change: transform; -} -.ol-touch .ol-control button { - font-size: 1.5em; -} -.ol-touch .ol-zoom-extent { - top: 5.5em; -} -.ol-control button:hover, -.ol-control button:focus { - text-decoration: none; - background-color: rgba(0,60,136,0.7); -} -.ol-zoom .ol-zoom-in { - border-radius: 2px 2px 0 0; -} -.ol-zoom .ol-zoom-out { - border-radius: 0 0 2px 2px; -} - - -.ol-attribution { - text-align: right; - bottom: .5em; - right: .5em; - max-width: calc(100% - 1.3em); -} - -.ol-attribution ul { - margin: 0; - padding: 0 .5em; - font-size: .7rem; - line-height: 1.375em; - color: #000; - text-shadow: 0 0 2px #fff; -} -.ol-attribution li { - display: inline; - list-style: none; - line-height: inherit; -} -.ol-attribution li:not(:last-child):after { - content: " "; -} -.ol-attribution img { - max-height: 2em; - max-width: inherit; - vertical-align: middle; -} -.ol-attribution ul, .ol-attribution button { - display: inline-block; -} -.ol-attribution.ol-collapsed ul { - display: none; -} -.ol-attribution:not(.ol-collapsed) { - background: rgba(255,255,255,0.8); -} -.ol-attribution.ol-uncollapsible { - bottom: 0; - right: 0; - border-radius: 4px 0 0; - height: 1.1em; - line-height: 1em; -} -.ol-attribution.ol-uncollapsible img { - margin-top: -.2em; - max-height: 1.6em; -} -.ol-attribution.ol-uncollapsible button { - display: none; -} - -.ol-zoomslider { - top: 4.5em; - left: .5em; - height: 200px; -} -.ol-zoomslider button { - position: relative; - height: 10px; -} - -.ol-touch .ol-zoomslider { - top: 5.5em; -} - -.ol-overviewmap { - left: 0.5em; - bottom: 0.5em; -} -.ol-overviewmap.ol-uncollapsible { - bottom: 0; - left: 0; - border-radius: 0 4px 0 0; -} -.ol-overviewmap .ol-overviewmap-map, -.ol-overviewmap button { - display: inline-block; -} -.ol-overviewmap .ol-overviewmap-map { - border: 1px solid #7b98bc; - height: 150px; - margin: 2px; - width: 150px; -} -.ol-overviewmap:not(.ol-collapsed) button{ - bottom: 1px; - left: 2px; - position: absolute; -} -.ol-overviewmap.ol-collapsed .ol-overviewmap-map, -.ol-overviewmap.ol-uncollapsible button { - display: none; -} -.ol-overviewmap:not(.ol-collapsed) { - background: rgba(255,255,255,0.8); -} -.ol-overviewmap-box { - border: 2px dotted rgba(0,60,136,0.7); -} - -.ol-overviewmap .ol-overviewmap-box:hover { - cursor: move; -} diff --git a/lib/galaxy/visualization/plugins/plugin.py b/lib/galaxy/visualization/plugins/plugin.py index e3bdf0e03d3c..bcd8c57098c7 100644 --- a/lib/galaxy/visualization/plugins/plugin.py +++ b/lib/galaxy/visualization/plugins/plugin.py @@ -80,12 +80,11 @@ def __init__(self, app, path, name, config, context=None, **kwargs): base_url = context.get("base_url", "") self.base_url = "/".join((base_url, self.name)) if base_url else self.name self.static_path = self._get_static_path(self.path) - if self.static_path and os.path.exists(os.path.join(self.static_path, "logo.png")): - self.config["logo"] = f"{self.static_path}/logo.png" template_cache_dir = context.get("template_cache_dir", None) additional_template_paths = context.get("additional_template_paths", []) self._set_up_template_plugin(template_cache_dir, additional_template_paths=additional_template_paths) self.resource_parser = resource_parser.ResourceParser(app) + self._set_logo() def render(self, trans=None, embedded=None, **kwargs): """ @@ -232,6 +231,15 @@ def _parse_embedded(self, embedded): # as is for now return embedded + def _set_logo(self): + if self.static_path: + supported_formats = ["png", "svg"] + for file_format in supported_formats: + logo_path = os.path.join(self.static_path, f"logo.{file_format}") + if os.path.isfile(logo_path): + self.config["logo"] = logo_path + return + class ScriptVisualizationPlugin(VisualizationPlugin): """