Commit 374b55fd authored by Piotr Gawron's avatar Piotr Gawron
Browse files

merge seantic-zoom changes into master

parent 01230ee5
minerva (12.1.0~beta.4) experimental; urgency=medium
* Bug fix: partial zooming is disabled due to issues with hierarchical overlay
* Bug fix: search results were not visible after initial search on top map
* Bug fix: going to export page and back was breaking a map
* Bug fix: export of special characters in pdf is working
-- Piotr Gawron <piotr.gawron@uni.lu> Wed, 17 Oct 2018 14:00:00 +0200
minerva (12.1.0~beta.3) experimental; urgency=medium
* Bug fix: double login with new LDAP credentials doesn't raise error
* Bug fix: empty LDAP filter doesn't raise error
* Bug fix: migration scripts work with database without superadmin privileges
* Bug fix: export didn't work
* Bug fix: coordinates of selected area wasn't processed properly when they
exceeded canvas
-- Piotr Gawron <piotr.gawron@uni.lu> Thu, 11 Oct 2018 14:00:00 +0200
minerva (12.1.0~beta.2) experimental; urgency=medium
* Bug fix: postgres migration script fixed to work with new docker compose
* Bug fix: double click on user add button disabled
* Bug fix: privileges are mirrored correctly across different popups
* Bug fix: plugin tab css fixed
* Small improvement: all ldap parameters are configurable
-- Piotr Gawron <piotr.gawron@uni.lu> Tue, 2 Oct 2018 11:00:00 +0200
minerva (12.1.0~beta.1) experimental; urgency=medium
* Bug fix: uploading sbml file with no ids in glyphs returned error that
could not be easily understand
* Bug fix: sometimes single variant in genomic view was hidden from initial
view
* Bug fix: ds_store files in subfolders crashed zip upload
* Bug fix: when creating new user default privileges were not filled
minerva (12.1.0) stable; urgency=medium
* Small improvement: default privilege value for 'Custom overlays' added
* Small improvement: explicit logging of successful and unsuccessful logins
* Small improvement: clicking on search result icon (on the map) change tab to
the corresponding search results
* Bug fix: passwords in the configuration tab are hidden with '*'
* Bug fix: user has access to transparency level when creating custom semantic
view (without this parametere functionality was very difficult to use)
* Bug fix: loading invalid plugin doesn't render empty div anymore
* Bug fix: sorting of custom overlays was broken when description of overlay
was present
* Bug fix: when there is a problem with adjusting font in complexes (because
the font should be smaller than 1pt) description is not drawn anymore
-- Piotr Gawron <piotr.gawron@uni.lu> Tue, 18 Sep 2018 20:00:00 +0200
minerva (12.1.0~beta.0) experimental; urgency=medium
* Small improvement: option to remove additional overlays generated by custom
semantic zoom
* Small improvement: 'Reduced modulation' edge was displayed differently in
CellDesigner and Minerva
* Small improvement: user-friendly documentation for plugin URL field
* Small improvement: plugins have to access information about active submap
* Small improvement: miriam support for VMH reaction and VMH metabolite
-- Piotr Gawron <piotr.gawron@uni.lu> Wed, 05 Sep 2018 17:00:00 +0200
minerva (12.1.0~alpha.0) experimental; urgency=medium
* Feature: genome browser with gene variants
* Feature: support of all CellDesigner element modifications
* Feature: ldap authentication
* Feature: multicolored anchors for data overlays
* Feature: minerva is distributed using rpm packages
* Bug fix: annotations for elements with mutation in name (like "BID (p15)")
weren't provided properly
* Small improvement: annotations from RHEA are handled
* Small improvement: changing of Terms of Service url allows admin to reset
the status of ToS acceptance for all users
* Small improvement: description of a grouped results in improved
* Small improvement: selection of required annotation on map upload improved
* Bug fix: annotations for elements with mutation in name (like "BID (p15)")
weren't provided properly
* Bug fix: passwords in the configuration tab are hidden with '*'
* Bug fix: user has access to transparency level when creating custom semantic
view (without this parametere functionality was very difficult to use)
* Bug fix: loading invalid plugin doesn't render empty div anymore
* Bug fix: sorting of custom overlays was broken when description of overlay
was present
* Bug fix: when there is a problem with adjusting font in complexes (because
the font should be smaller than 1pt) description is not drawn anymore
* Bug fix: going to export page and back was breaking a map
* Bug fix: coordinates of selected area wasn't processed properly when they
exceeded canvas
* Bug fix: postgres migration script fixed to work with new docker compose
* Bug fix: double click on user add button disabled
* Bug fix: privileges are mirrored correctly across different popups
* Bug fix: plugin tab css fixed
* Bug fix: uploading sbml file with no ids in glyphs returned error that
could not be easily understand
* Bug fix: ds_store files in subfolders crashed zip upload
* Bug fix: when creating new user default privileges were not filled
-- Piotr Gawron <piotr.gawron@uni.lu> Fri, 03 Aug 2018 10:00:00 +0200
-- Piotr Gawron <piotr.gawron@uni.lu> Mon, 29 Oct 2018 13:00:00 +0200
minerva (12.0.4) stable; urgency=medium
* Bug fix: CellDesigner modifications that are drawn as reaction are handled
......
......@@ -29,6 +29,7 @@ function CommentDialog(params) {
var self = this;
self._createGui();
$(self.getElement()).dialog({
title: "Add comment",
autoOpen: false,
resizable: false,
width: window.innerWidth / 2,
......
......@@ -39,8 +39,10 @@ Legend.prototype._initializeGui = function () {
var legendDiv = Functions.createElement({
type: "div",
id: "legend-div",
className: "carousel slide"
className: "carousel"
});
legendDiv.setAttribute("data-ride", "carousel");
self.getElement().appendChild(legendDiv);
var indicators = Functions.createElement({
......
......@@ -286,11 +286,6 @@ AddProjectDialog.prototype.createGeneralTabContent = function () {
help: 'If this checkbox is checked, the uploaded model will be displayed in SBGN format, instead of default ' +
'CellDesigner format.'
}));
table.appendChild(self.createCheckboxRow({
labelName: "Custom semantic zooming:",
defaultValue: false,
inputName: "project-semantic-zooming"
}));
table.appendChild(self.createCheckboxRow({
labelName: "Custom semantic zooming contains multiple overlays:",
defaultValue: false,
......@@ -709,7 +704,6 @@ AddProjectDialog.prototype.init = function () {
self.bindProjectUploadPreferences(user, "autoResize", "project-auto-margin");
self.bindProjectUploadPreferences(user, "validateMiriam", "project-verify-annotations");
self.bindProjectUploadPreferences(user, "cacheData", "project-cache-data");
self.bindProjectUploadPreferences(user, "semanticZooming", "project-semantic-zooming");
self.bindProjectUploadPreferences(user, "semanticZoomingContainsMultipleOverlays", "project-semantic-zooming-contains-multiple-overlays");
self.bindProjectUploadPreferences(user, "sbgn", "project-sbgn-visualization");
});
......@@ -1072,14 +1066,6 @@ AddProjectDialog.prototype.isSbgn = function () {
return $("[name='project-sbgn-visualization']", this.getElement()).is(':checked');
};
/**
*
* @returns {boolean}
*/
AddProjectDialog.prototype.isSemanticZooming = function () {
return $("[name='project-semantic-zooming']", this.getElement()).is(':checked');
};
/**
*
* @returns {boolean}
......@@ -1158,7 +1144,6 @@ AddProjectDialog.prototype.onSaveClicked = function () {
"organism": self.getOrganism(),
"mapCanvasType": self.getMapCanvasTypeId(),
"sbgn": self.isSbgn(),
"semantic-zoom": self.isSemanticZooming(),
"semantic-zoom-contains-multiple-layouts": self.isSemanticZoomingContainsMultipleOverlays(),
"annotate": self.isAnnotateAutomatically(),
"verify-annotations": self.isVerifyAnnotations(),
......
......@@ -83,7 +83,7 @@ OpenLayerPolyline.prototype.isShown = function () {
OpenLayerPolyline.prototype.getBounds = function () {
var self = this;
var extent = self.getOpenLayersRectangle().getGeometry().getExtent();
var extent = self.getOpenLayersPolyline().getGeometry().getExtent();
var projection1 = [extent[0], extent[1]];
var p1 = self.getMap().fromProjectionToPoint(projection1);
......
......@@ -56,7 +56,6 @@ UserPreferences.prototype.update = function (userPreferences) {
* @param {boolean} projectUpload.validate-miriam
* @param {boolean} projectUpload.validate-miriam
* @param {boolean} projectUpload.cache-data
* @param {boolean} projectUpload.semantic-zooming
* @param {boolean} projectUpload.sbgn
*/
UserPreferences.prototype.setProjectUpload = function (projectUpload) {
......@@ -65,7 +64,6 @@ UserPreferences.prototype.setProjectUpload = function (projectUpload) {
validateMiriam: projectUpload["validate-miriam"],
annotateModel: projectUpload["annotate-model"],
cacheData: projectUpload["cache-data"],
semanticZooming: projectUpload["semantic-zooming"],
semanticZoomingContainsMultipleOverlays: projectUpload["semantic-zooming-contains-multiple-overlays"],
sbgn: projectUpload["sbgn"]
};
......@@ -183,7 +181,6 @@ UserPreferences.prototype.toExport = function () {
"annotate-model": this._projectUpload.annotateModel,
"cache-data": this._projectUpload.cacheData,
"sbgn": this._projectUpload.sbgn,
"semantic-zooming": this._projectUpload.semanticZooming,
"semantic-zooming-contains-multiple-overlays":this._projectUpload.semanticZoomingContainsMultipleOverlays
},
"element-annotators": this._elementAnnotators,
......
......@@ -87,7 +87,7 @@ ReactionSurface.prototype.setColor = function (color) {
strokeColor: color
});
}
this.customized = true;
this.setCustomized(true);
};
/**
......@@ -163,7 +163,7 @@ ReactionSurface.prototype.changedToDefault = function () {
strokeWeight: 5
});
}
this.customized = false;
this.setCustomized(false);
};
/**
......@@ -177,7 +177,7 @@ ReactionSurface.prototype.changedToCustomized = function () {
strokeWeight: this.getWidth()
});
}
this.customized = true;
this.setCustomized(true);
};
/**
......
"use strict";
require("../../../mocha-config");
// noinspection JSUnusedLocalSymbols
var logger = require('../../../logger');
var OpenLayerCanvas = require('../../../../../main/js/map/canvas/OpenLayers/OpenLayerCanvas');
var OpenLayerPolyline = require('../../../../../main/js/map/canvas/OpenLayers/OpenLayerPolyline');
var Bounds = require('../../../../../main/js/map/canvas/Bounds');
var Point = require('../../../../../main/js/map/canvas/Point');
var SelectionContextMenu = require('../../../../../main/js/gui/SelectionContextMenu');
var chai = require('chai');
var assert = chai.assert;
describe('OpenLayerPolyline', function () {
var testOptions = {
center: new Point(0, 0),
tileSize: 256,
width: 300,
height: 600,
zoom: 3,
minZoom: 2,
maxZoom: 10,
backgroundOverlays: [{
id: 1,
name: "overlay",
directory: "overlay_dir"
}]
};
it("getBounds", function () {
var canvas = new OpenLayerCanvas(testDiv, testOptions);
var path = [new Point(0, 0), new Point(10, 5)];
var polyline = canvas.createPolyline({
strokeWeight: 1,
strokeColor: "#00ff00",
path: path
});
polyline.show();
assert.ok(polyline.getBounds());
});
});
......@@ -6,12 +6,12 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.log4j.Logger;
import lcsb.mapviewer.common.Configuration;
import lcsb.mapviewer.common.exception.InvalidStateException;
import lcsb.mapviewer.common.exception.NotImplementedException;
import lcsb.mapviewer.model.map.BioEntity;
import lcsb.mapviewer.model.map.compartment.Compartment;
import lcsb.mapviewer.model.map.compartment.PathwayCompartment;
import lcsb.mapviewer.model.map.layout.graphics.Layer;
......@@ -60,8 +60,8 @@ public class CreateHierarchyCommand extends ModelCommand {
private double maxZoomFactor;
/**
* Default constructor that intializes data.
*
* Default constructor that initializes data.
*
* @param model
* model on which command will be executed
* @param maxZoomFactor
......@@ -105,12 +105,21 @@ public class CreateHierarchyCommand extends ModelCommand {
setParentingAndChildreningOfNonComplexChildrens(sortedAliases);
model.getElements().addAll(compacts);
sortedAliases = model.getElementsSortedBySize();
preSettingOfVisibilityLevel(sortedAliases, maxZoomFactor);
settingOfTransparencyLevel(sortedAliases);
setDefaultVisibilityLevel(sortedAliases);
setStatus(ModelCommandStatus.EXECUTED);
}
private void setDefaultVisibilityLevel(List<Element> sortedAliases) {
for (Element element: sortedAliases) {
if (element.getVisibilityLevel()==null||element.getVisibilityLevel().isEmpty()) {
element.setVisibilityLevel(0);
}
}
}
@Override
protected void redoImplementation() {
throw new NotImplementedException();
......@@ -122,10 +131,9 @@ public class CreateHierarchyCommand extends ModelCommand {
protected void clean() {
for (Element alias : getModel().getElements()) {
alias.setCompartment(null);
alias.setTransparencyLevel("");
}
for (BioEntity bioEntity : getModel().getBioEntities()) {
bioEntity.setVisibilityLevel("0");
if (alias.getTransparencyLevel() == null || alias.getTransparencyLevel().isEmpty()) {
alias.setTransparencyLevel("");
}
}
Set<Compartment> toRemove = new HashSet<>();
for (Compartment alias : getModel().getCompartments()) {
......@@ -183,16 +191,8 @@ public class CreateHierarchyCommand extends ModelCommand {
assignToCompartments();
}
/**
* Computes visibility levels for aliases based on the size.
*
* @param sortedAliases
* list of aliases
* @param maxZoomFactor
* max scale used on the map
*/
private void preSettingOfVisibilityLevel(List<Element> sortedAliases, double maxZoomFactor) {
for (Element alias : sortedAliases) {
private int computeVisibility(Element alias) {
if (!NumberUtils.isNumber(alias.getVisibilityLevel())) {
double rate = computeRate(alias, Configuration.MIN_VISIBLE_OBJECT_SIZE);
int logValue = (int) ((int) Math.ceil(Math.log(rate)) / LOG_4);
boolean hasCompartment = alias.getCompartment() != null;
......@@ -210,63 +210,73 @@ public class CreateHierarchyCommand extends ModelCommand {
logValue = zoomLevels;
}
}
alias.setVisibilityLevel(logValue + "");
return logValue;
} else {
return Integer.valueOf(alias.getVisibilityLevel());
}
}
/**
* Sets transparency level in hierarchical view for compartment alias.
*
*
* @param compartment
* comaprtment alias
* compartment alias
*/
private void settingTransparencyLevelForCompartment(Compartment compartment) {
int maxVisibilityLevel = Integer.MAX_VALUE;
double rate = computeRate(compartment, Configuration.MAX_VISIBLE_OBJECT_SIZE);
maxVisibilityLevel = (int) ((int) Math.ceil(Math.log(rate)) / LOG_4);
for (Element child : compartment.getElements()) {
maxVisibilityLevel = Math.min(maxVisibilityLevel, Integer.valueOf(child.getVisibilityLevel()));
}
if (maxVisibilityLevel >= zoomLevels) {
maxVisibilityLevel = zoomLevels;
}
if (maxVisibilityLevel <= 0) {
maxVisibilityLevel = 1;
if (compartment.getTransparencyLevel() == null || compartment.getTransparencyLevel().isEmpty()) {
int maxVisibilityLevel = Integer.MAX_VALUE;
double rate = computeRate(compartment, Configuration.MAX_VISIBLE_OBJECT_SIZE);
maxVisibilityLevel = (int) ((int) Math.ceil(Math.log(rate)) / LOG_4);
for (Element child : compartment.getElements()) {
maxVisibilityLevel = Math.min(maxVisibilityLevel, Integer.valueOf(computeVisibility(child)));
}
if (maxVisibilityLevel >= zoomLevels) {
maxVisibilityLevel = zoomLevels;
}
if (maxVisibilityLevel <= 0) {
maxVisibilityLevel = 1;
}
compartment.setTransparencyLevel(maxVisibilityLevel + "");
}
compartment.setTransparencyLevel(maxVisibilityLevel + "");
for (Element child : compartment.getElements()) {
child.setVisibilityLevel(compartment.getTransparencyLevel());
if (child.getVisibilityLevel() == null || child.getVisibilityLevel().isEmpty()) {
child.setVisibilityLevel(compartment.getTransparencyLevel());
}
}
}
/**
* Sets transparency level in hierarchical view for complex alias.
*
*
* @param complex
* complex alias
*/
private void settingTransparencyLevelForComplex(Complex complex) {
int maxVisibilityLevel = Integer.MAX_VALUE;
double rate = computeRate(complex, Configuration.MAX_VISIBLE_OBJECT_SIZE);
maxVisibilityLevel = (int) ((int) Math.ceil(Math.log(rate)) / LOG_4);
for (Element child : complex.getElements()) {
maxVisibilityLevel = Math.min(maxVisibilityLevel, Integer.valueOf(child.getVisibilityLevel()));
}
if (maxVisibilityLevel >= zoomLevels) {
maxVisibilityLevel = zoomLevels;
}
if (maxVisibilityLevel <= 0) {
maxVisibilityLevel = 1;
if (complex.getTransparencyLevel() == null || complex.getTransparencyLevel().isEmpty()) {
int maxVisibilityLevel = Integer.MAX_VALUE;
double rate = computeRate(complex, Configuration.MAX_VISIBLE_OBJECT_SIZE);
maxVisibilityLevel = (int) ((int) Math.ceil(Math.log(rate)) / LOG_4);
for (Element child : complex.getElements()) {
maxVisibilityLevel = Math.min(maxVisibilityLevel, Integer.valueOf(computeVisibility(child)));
}
if (maxVisibilityLevel >= zoomLevels) {
maxVisibilityLevel = zoomLevels;
}
if (maxVisibilityLevel <= 0) {
maxVisibilityLevel = 1;
}
complex.setTransparencyLevel(maxVisibilityLevel + "");
}
complex.setTransparencyLevel(maxVisibilityLevel + "");
for (Element child : complex.getElements()) {
child.setVisibilityLevel(complex.getTransparencyLevel());
if (child.getVisibilityLevel() == null || child.getVisibilityLevel().isEmpty()) {
child.setVisibilityLevel(complex.getTransparencyLevel());
}
}
}
/**
* Sets transparency level in hierarchical view for all elements.
*
*
* @param sortedAliases
* list of aliases
*/
......@@ -277,14 +287,16 @@ public class CreateHierarchyCommand extends ModelCommand {
} else if (alias instanceof Complex) {
settingTransparencyLevelForComplex((Complex) alias);
} else {
alias.setTransparencyLevel("0");
if (alias.getTransparencyLevel() == null || alias.getTransparencyLevel().isEmpty()) {
alias.setTransparencyLevel("0");
}
}
}
}
/**
* Removes invalid compartment children.
*
*
* @param sortedAliases
* list of aliases
*/
......@@ -304,7 +316,7 @@ public class CreateHierarchyCommand extends ModelCommand {
/**
* Sets parent for elements.
*
*
* @param sortedAliases
* list of aliases
*/
......@@ -337,7 +349,7 @@ public class CreateHierarchyCommand extends ModelCommand {
/**
* Set parents for the elements in hierarchical view.
*
*
* @param sortedAliases
* list of aliases
*/
......@@ -369,11 +381,11 @@ public class CreateHierarchyCommand extends ModelCommand {
/**
* Computes the ratio between the minimal object that should be visible, and
* alias visible on the top level.
*
*
* @param alias
* alias for which computation is done
* @param limit
* size of the minimal visibe object
* size of the minimal visible object
* @return ratio between the minimal object that should be visible, and alias
* visible on the top level
*/
......
......@@ -9,7 +9,9 @@ import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
......@@ -25,6 +27,7 @@ import lcsb.mapviewer.model.map.compartment.PathwayCompartment;
import lcsb.mapviewer.model.map.model.Model;
import lcsb.mapviewer.model.map.species.Element;
import lcsb.mapviewer.model.map.species.Species;
import lcsb.mapviewer.modelutils.map.ElementUtils;
public class CreateHierarchyCommandTest extends CommandTestFunctions {
Logger logger = Logger.getLogger(CreateHierarchyCommandTest.class);
......@@ -304,4 +307,71 @@ public class CreateHierarchyCommandTest extends CommandTestFunctions {
}
}
@Test
public void testHierarchyWithCustomSemanticZooming() throws Exception {
try {
Model model = getModelForFile("testFiles/custom_semantic_zooming.xml", false);
Map<Element, String> visibilityLevels = new HashMap<>();
for (Element element : model.getElements()) {
if (element.getVisibilityLevel() != null && !element.getVisibilityLevel().isEmpty()) {
visibilityLevels.put(element, element.getVisibilityLevel());
}
}
new CreateHierarchyCommand(model, 4, 80).execute();
for (Element element : model.getElements()) {
if (visibilityLevels.get(element) != null) {
assertEquals("Visibility level changed, but shouldn't", visibilityLevels.get(element),
element.getVisibilityLevel());
}
}
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
@Test
public void testHierarchyWithCustomSemanticZoomingPathwayLevels() throws Exception {
try {
ElementUtils eu = new ElementUtils();
Model model = getModelForFile("testFiles/custom_semantic_zooming.xml", false);
Map<Element, String> visibilityLevels = new HashMap<>();
for (Element element : model.getElements()) {
if (element.getVisibilityLevel() != null && !element.getVisibilityLevel().isEmpty()) {
visibilityLevels.put(element, element.getVisibilityLevel());
}
}
new CreateHierarchyCommand(model, 4, 80).execute();
for (Element element : model.getElements()) {
if (visibilityLevels.get(element) == null) {
int visibilityLevel = Integer.parseInt(element.getVisibilityLevel());
if (element.getCompartment() != null) {
int parentTransparency = Integer.parseInt(element.getCompartment().getTransparencyLevel());
assertEquals(
eu.getElementTag(element) + eu.getElementTag(element.getCompartment())
+ "Element should be directly visible when parent is transparent",
parentTransparency, visibilityLevel);