diff --git a/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js b/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js index 30faa341b633ce1991ada5dc038ed710a36f6b43..931d88743cb4d3bbbc23cc1ed577d39d26de896d 100644 --- a/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js +++ b/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js @@ -9,6 +9,7 @@ var Alias = require('../../map/data/Alias'); var InvalidArgumentError = require('../../InvalidArgumentError'); var PanelControlElementType = require('../PanelControlElementType'); var Reaction = require('../../map/data/Reaction'); +var SearchBioEntityGroup = require('../../map/data/SearchBioEntityGroup'); // noinspection JSUnusedLocalSymbols var logger = require('../../logger'); @@ -52,6 +53,8 @@ GenericSearchPanel.prototype.createTableElement = function (element, icon) { return this.createAliasElement(element, icon); } else if (element instanceof Reaction) { return this.createReactionElement(element); + } else if (element instanceof SearchBioEntityGroup) { + return this.createSearchBioEntityGroupElement(element); } else { throw new Error("Unknown element type: " + element.constructor.name); } @@ -95,6 +98,21 @@ GenericSearchPanel.prototype.createAliasElement = function (alias, icon) { return result; }; +GenericSearchPanel.prototype.createSearchBioEntityGroupElement = function (group, icon) { + var self = this; + var guiUtils = self.getGuiUtils(); + + var result = document.createElement("tr"); + var td = document.createElement("td"); + result.appendChild(td); + var div = guiUtils.createSearchBioEntityGroupElement(group); + + div.appendChild(guiUtils.createSeparator()); + td.appendChild(div); + + return result; +}; + GenericSearchPanel.prototype.searchByQuery = function () { var self = this; var query = this.getControlElement(PanelControlElementType.SEARCH_INPUT).value; @@ -123,7 +141,7 @@ GenericSearchPanel.prototype.refreshSearchAutocomplete = function () { GenericSearchPanel.prototype.init = function () { var query = ServerConnector.getSessionData().getSearchQuery(); if (query !== undefined) { - return this.getOverlayDb().searchByEncodedQuery(query, false).catch(function(error){ + return this.getOverlayDb().searchByEncodedQuery(query, false).catch(function (error) { if (error instanceof InvalidArgumentError) { logger.warn(error.message); } else { diff --git a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js index 09fc55fa0769c2beab7a7cb6ced8db7b91a92841..eb87fa1b81772d7592a3aa2fd2b5d3c2b6b6e011 100644 --- a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js +++ b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js @@ -2,6 +2,8 @@ /* exported logger */ +var Alias = require('../../map/data/Alias'); + var GuiConnector = require('../../GuiConnector'); var AbstractGuiElement = require('../AbstractGuiElement'); var Functions = require('../../Functions'); @@ -185,7 +187,7 @@ GuiUtils.prototype.createAnnotationList = function (annotations, options) { var annotators = this.getConfiguration().getAnnotators(); var annotatorsClassMapping = {}; for (var i = 0; i < annotators.length; i++) { - annotatorsClassMapping[annotators[i].getClassName()] = annotators[i]; + annotatorsClassMapping[annotators[i].getClassName()] = annotators[i]; } var grouppedAnnotations = {}; @@ -198,8 +200,8 @@ GuiUtils.prototype.createAnnotationList = function (annotations, options) { // = annotatorClasName ? annotatorsClassMapping[annotatorClasName].getName() : "Annotated by curator"; var cntAnnotations = 0; - - Object.keys(grouppedAnnotations).sort().forEach(function(annotatorClass){ + + Object.keys(grouppedAnnotations).sort().forEach(function (annotatorClass) { // var desc = grouppedAnnotations.keys()[i]; var groupContainer = (inline ? document.createElement("span") : document.createElement("div")); @@ -210,16 +212,16 @@ GuiUtils.prototype.createAnnotationList = function (annotations, options) { if (inline) { descContainer.innerHTML = annotatorName + ': '; } else { - descContainer.innerHTML = annotatorName; - + descContainer.innerHTML = annotatorName; + if (annotatorClass) { var annotatorDescription = annotatorsClassMapping[annotatorClass].getDescription(); if (annotatorDescription) { var tooltipContainer = Functions.createElement({ - type: "span" + type: "span" }); tooltipContainer.appendChild(Functions.createElement({ - type: "span", + type: "span", className: "glyphicon glyphicon-question-sign tooltip-icon" })); tooltipContainer.appendChild(Functions.createElement({ @@ -230,19 +232,19 @@ GuiUtils.prototype.createAnnotationList = function (annotations, options) { descContainer.appendChild(tooltipContainer); } - } - } + } + } descContainer.className = "minerva-annotation-group-header"; if (!inline) groupContainer.className = "minerva-annotation-group"; groupContainer.appendChild(descContainer); - if (inline){ + if (inline) { var par = document.createElement("span"); par.innerHTML = "("; groupContainer.appendChild(par); } - grouppedAnnotations[annotatorClass] = grouppedAnnotations[annotatorClass].sort(function(a, b) { + grouppedAnnotations[annotatorClass] = grouppedAnnotations[annotatorClass].sort(function (a, b) { const aType = a.getType().toUpperCase(); const bType = b.getType().toUpperCase(); if (aType < bType) return -1; @@ -258,9 +260,9 @@ GuiUtils.prototype.createAnnotationList = function (annotations, options) { var link = self.createAnnotationLink(element, showType); if (inline) { if (j > 0) { - var coma = document.createElement("span"); - coma.innerHTML = ", "; - groupContainer.appendChild(coma); + var coma = document.createElement("span"); + coma.innerHTML = ", "; + groupContainer.appendChild(coma); } groupContainer.appendChild(link); } else { @@ -268,9 +270,9 @@ GuiUtils.prototype.createAnnotationList = function (annotations, options) { var row = document.createElement("div"); row.style.height = "26px"; if (j % 2 === 0) { - row.className = "minerva-annotation-row-odd"; + row.className = "minerva-annotation-row-odd"; } else { - row.className = "minerva-annotation-row-even"; + row.className = "minerva-annotation-row-even"; } var header = document.createElement("div"); @@ -287,15 +289,15 @@ GuiUtils.prototype.createAnnotationList = function (annotations, options) { } } - if (inline){ - var par = document.createElement("span"); - par.innerHTML = ")"; - groupContainer.appendChild(par); + if (inline) { + var par = document.createElement("span"); + par.innerHTML = ")"; + groupContainer.appendChild(par); } result.appendChild(groupContainer); }); - + return result; }; @@ -347,13 +349,16 @@ GuiUtils.prototype.createParamLine = function (label, value) { return result; }; -GuiUtils.prototype.createIcon = function (icon) { +GuiUtils.prototype.createIcon = function (icon, onclickFunction) { var result = document.createElement("div"); if (icon !== undefined && icon !== null) { var img = document.createElement("img"); img.src = GuiConnector.getImgPrefix() + icon; img.style.float = "left"; img.hspace = "5"; + if (onclickFunction !== undefined) { + img.onclick = onclickFunction; + } result.appendChild(img); } return result; @@ -441,7 +446,6 @@ GuiUtils.prototype.createReactionElement = function (params) { div.appendChild(self.createReactantsLine(reaction.getReactants())); div.appendChild(self.createProductsLine(reaction.getProducts())); div.appendChild(self.createModifiersLine(reaction.getModifiers())); - div.appendChild(self.createCandidates("Candidates: ", reaction.getOther('dataMining'))); div.appendChild(self.createAnnotations("Annotations: ", reaction.getReferences())); return div; }; @@ -455,7 +459,15 @@ GuiUtils.prototype.createAliasElement = function (params) { if (showTitle) { if (icon !== undefined) { - div.appendChild(this.createIcon(icon)); + div.appendChild(this.createIcon(icon, function () { + return self.getMap().openSubmap(alias.getModelId()).then(function () { + if (alias instanceof Alias) { + return self.getMap().getSubmapById(alias.getModelId()).fitBounds([alias]); + } else { + return self.getMap().getSubmapById(alias.getModelId()).fitBounds(alias.getBioEntities()); + } + }); + })); } div.appendChild(this.createParamLine(alias.getType() + ": ", alias.getName())); @@ -480,11 +492,17 @@ GuiUtils.prototype.createAliasElement = function (params) { div.appendChild(self.createParamLine("Charge: ", alias.getCharge())); div.appendChild(self.createArrayParamLine("Synonyms: ", alias.getSynonyms())); div.appendChild(self.createLabelText(alias.getDescription())); - div.appendChild(self.createCandidates("Candidates: ", alias.getOther('dataMining'))); - div.appendChild(self.createChebiTree("Chebi ontology: ", alias.getOther('chebiTree'))); + // div.appendChild(self.createChebiTree("Chebi ontology: ", alias.getOther('chebiTree'))); div.appendChild(self.createAnnotations("Annotations: ", alias.getReferences())); return div; }; +GuiUtils.prototype.createSearchBioEntityGroupElement = function (group) { + if (group.getBioEntities()[0] instanceof Alias) { + return this.createAliasElement({alias: group, icon: group.getIcon()}); + } else { + return this.createReactionElement({reaction: group, icon: group.getIcon()}); + } +}; GuiUtils.prototype.createReactantsLine = function (label, value) { var result = document.createElement("div"); diff --git a/frontend-js/src/main/js/map/AbstractCustomMap.js b/frontend-js/src/main/js/map/AbstractCustomMap.js index bd2c5e06bafe23397b2cc60f3adf9e5e745a1a63..ff7a66e80fd7a01599e106ce57a04ff8fdc4c121 100644 --- a/frontend-js/src/main/js/map/AbstractCustomMap.js +++ b/frontend-js/src/main/js/map/AbstractCustomMap.js @@ -5,12 +5,14 @@ var Promise = require("bluebird"); var logger = require('../logger'); var functions = require('../Functions'); +var Alias = require('./data/Alias'); var AliasInfoWindow = require('./window/AliasInfoWindow'); var AliasSurface = require('./surface/AliasSurface'); var GuiConnector = require('../GuiConnector'); var IdentifiedElement = require('./data/IdentifiedElement'); var ObjectWithListeners = require('../ObjectWithListeners'); var PointInfoWindow = require('./window/PointInfoWindow'); +var Reaction = require('./data/Reaction'); var ReactionInfoWindow = require('./window/ReactionInfoWindow'); var ReactionSurface = require('./surface/ReactionSurface'); @@ -1088,7 +1090,7 @@ AbstractCustomMap.prototype.getBounds = function () { p2: this.fromLatLngToPoint(sw) }; if (result.p2.x > result.p1.x) { - result.p2.x -= 360 * self.pixelsPerLonDegree_*self.zoomFactor; + result.p2.x -= 360 * self.pixelsPerLonDegree_ * self.zoomFactor; } return result; }; @@ -1097,14 +1099,13 @@ AbstractCustomMap.prototype.getBounds = function () { /** * Sets zoom level for google maps. * - * @param mapIdentifier - * id of the model for which we change zoom level * @param zoom * new zoom level on map */ AbstractCustomMap.prototype.setZoom = function (zoom) { - if (this.initialized) { - return Promise.resolve(this.getGoogleMap().setZoom(zoom)); + var self = this; + if (self.initialized) { + return Promise.resolve(self.getGoogleMap().setZoom(zoom)); } else { logger.warn("cannot change zoom for map that is not opened yet"); return Promise.resolve(); @@ -1118,21 +1119,66 @@ AbstractCustomMap.prototype.getZoom = function () { AbstractCustomMap.prototype.fitBounds = function (markers) { var self = this; var map = self.getGoogleMap(); - if (map !== undefined) { - var bounds = new google.maps.LatLngBounds(); - + if (map !== undefined && markers.length > 0) { + var minX = self.getModel().getWidth(); + var minY = self.getModel().getHeight(); + var maxX = 0; + var maxY = 0; for (var i = 0; i < markers.length; i++) { var marker = markers[i]; if (marker.getModelId() === self.getId()) { - var markerBounds = marker.getBounds(); - bounds.extend(markerBounds.getNorthEast()); - bounds.extend(markerBounds.getSouthWest()); + if (marker instanceof Alias) { + minX = Math.min(minX, marker.getX()); + minY = Math.min(minY, marker.getY()); + maxX = Math.max(maxX, marker.getX() + marker.getWidth()); + maxY = Math.max(maxY, marker.getY() + marker.getHeight()); + } else if (marker instanceof Reaction) { + minX = Math.min(minX, marker.getCenter().x); + minY = Math.min(minY, marker.getCenter().y); + maxX = Math.max(maxX, marker.getCenter().x); + maxY = Math.max(maxY, marker.getCenter().y); + } else { + var markerBounds = marker.getBounds(); + var p1 = self.fromLatLngToPoint(markerBounds.getNorthEast()); + var p2 = self.fromLatLngToPoint(markerBounds.getSouthWest()); + + minX = Math.min(minX, p2.x); + minY = Math.min(minY, p1.y); + maxX = Math.max(maxX, p1.x); + maxY = Math.max(maxY, p2.y); + } } } - if (!bounds.isEmpty()) { - return map.fitBounds(bounds); + var currentBounds = self.getBounds(); + + var xScale = (maxX - minX) / (currentBounds.p1.x - currentBounds.p2.x); + var yScale = (maxY - minY) / (currentBounds.p2.y - currentBounds.p1.y); + + var scale = Math.max(xScale, yScale); + + var zoom = self.getZoom(); + + while (scale > 1) { + zoom--; + scale /= 2; + } + if (scale <= 1e-6) { + zoom = self.getModel().getMaxZoom(); + } else { + while (scale < 0.5) { + zoom++; + scale *= 2; + } + } + + if (zoom > self.getModel().getMaxZoom()) { + zoom = self.getModel().getMaxZoom(); } + var center = new google.maps.Point((minX + maxX) / 2, (minY + maxY) / 2); + var centerLatLng = self.fromPointToLatLng(center); + return Promise.all([map.setCenter(centerLatLng), map.setZoom(zoom)]); } + return Promise.resolve(); }; diff --git a/frontend-js/src/main/js/map/CustomMap.js b/frontend-js/src/main/js/map/CustomMap.js index 96041ec35cf92f0c99c95ec72e6c448bb0bf9d74..66a7fa93f2bddba5982dd6b141959fb29bfdb4dc 100644 --- a/frontend-js/src/main/js/map/CustomMap.js +++ b/frontend-js/src/main/js/map/CustomMap.js @@ -433,6 +433,8 @@ CustomMap.prototype.openSubmap = function (id) { return self.refreshMarkers(true); } }); + } else { + return Promise.resolve(); } }; @@ -705,8 +707,6 @@ CustomMap.prototype.renderOverlayCollection = function (params) { var overlayCollection = params.overlayCollection; var elements; - var markers = []; - var submaps = self.getSubmaps().concat([self]); return overlayCollection.getIdentifiedElements().then(function (identifiedElements) { @@ -719,9 +719,6 @@ CustomMap.prototype.renderOverlayCollection = function (params) { } return Promise.all(promises); }).then(function (mapMarkers) { - for (var i = 0; i < mapMarkers.length; i++) { - markers = markers.concat(mapMarkers[i]); - } return Promise.each(elements, function (element) { var infoWindow = self.getInfoWindowForIdentifiedElement(element); if (infoWindow !== null && infoWindow !== undefined) { @@ -731,10 +728,12 @@ CustomMap.prototype.renderOverlayCollection = function (params) { } }); }).then(function () { + return self.fetchIdentifiedElements(elements); + }).then(function (fullElements) { var promises = []; if (elements.length > 0 && fitBounds) { for (var j = 0; j < submaps.length; j++) { - promises.push(submaps[j].fitBounds(markers)); + promises.push(submaps[j].fitBounds(fullElements)); } } return Promise.all(promises); @@ -1084,7 +1083,13 @@ CustomMap.prototype.fetchIdentifiedElements = function (elements, complete) { var modelId = modelIds[i]; promises.push(this.getSubmapById(modelId).getModel().getByIdentifiedElements(modelElements[modelId], complete)); } - return Promise.all(promises); + var result = []; + return Promise.all(promises).then(function (data) { + for (var i = 0; i < data.length; i++) { + result.push.apply(result, data[i]); + } + return result; + }); }; diff --git a/frontend-js/src/main/js/map/data/SearchBioEntityGroup.js b/frontend-js/src/main/js/map/data/SearchBioEntityGroup.js new file mode 100644 index 0000000000000000000000000000000000000000..bee43aa1ad2488796144079fca8f2670d7253723 --- /dev/null +++ b/frontend-js/src/main/js/map/data/SearchBioEntityGroup.js @@ -0,0 +1,223 @@ +"use strict"; + +var Alias = require("./Alias"); +var BioEntity = require("./BioEntity"); +var Reaction = require("./Reaction"); + +// noinspection JSUnusedLocalSymbols +var logger = require('../../logger'); + +/** + * Class representing merged search bioEntities. + * + * @param bioEntity + * initial bioEntity from which group is created + */ +function SearchAliasGroup(bioEntity) { + if (!(bioEntity instanceof BioEntity)) { + throw new Error("Invalid argument"); + } + this._bioEntites = [bioEntity]; +} + +SearchAliasGroup.prototype.bioEntityMatch = function (newBioEntity) { + var result = true; + var self = this; + + for (var i = 0; i < self._bioEntites.length; i++) { + var bioEntity = self._bioEntites[i]; + if (self.bioEntityComparator(bioEntity, newBioEntity) !== 0) { + result = false; + } + } + return result; +}; + +SearchAliasGroup.prototype.addBioEntity = function (newBioEntity) { + this._bioEntites.push(newBioEntity); +}; + +SearchAliasGroup.prototype.getBioEntities = function () { + return this._bioEntites; +}; + +SearchAliasGroup.prototype.bioEntityComparator = function (bioEntity1, bioEntity2) { + if (bioEntity1 instanceof Alias && bioEntity2 instanceof Alias) { + if (bioEntity1.getName() !== bioEntity2.getName()) { + return -1; + } + if (bioEntity1.getModelId() !== bioEntity2.getModelId()) { + return -2; + } + if (bioEntity1.getCompartmentId() !== bioEntity2.getCompartmentId()) { + return -3; + } + if (bioEntity1.getType() !== bioEntity2.getType()) { + return -4; + } + if (bioEntity1.getOther("structuralState") !== bioEntity2.getOther("structuralState")) { + return -5; + } + + var computeSerializedModifications = function (modifications) { + if (modifications === undefined) { + return []; + } + var result = []; + for (var i = 0; i < modifications.length; i++) { + var modification = modifications[i]; + result.push(modification.name + "_" + modification.state); + } + result.sort(); + return result; + }; + var serializedModifications1 = computeSerializedModifications(bioEntity1.getOther("modifications")); + var serializedModifications2 = computeSerializedModifications(bioEntity2.getOther("modifications")); + if (serializedModifications1.length !== serializedModifications2.length) { + return -6; + } + for (var i = 0; i < serializedModifications1.length; i++) { + if (serializedModifications1[i] !== serializedModifications2[i]) { + return -7; + } + } + return 0; + } + if (bioEntity1 instanceof Reaction && bioEntity2 instanceof Reaction) { + if (bioEntity1.getId() !== bioEntity2.getId()) { + return -8; + } + return 0; + } + return -9; +}; + +SearchAliasGroup.prototype.setIcon = function (icon) { + this._icon = icon; +}; + +SearchAliasGroup.prototype.getIcon = function () { + return this._icon; +}; + +//aggregated data +SearchAliasGroup.prototype.getType = function () { + return this._bioEntites[0].getType(); +}; + +SearchAliasGroup.prototype.getName = function () { + return this._bioEntites[0].getName(); +}; + +SearchAliasGroup.prototype.getModelId = function () { + return this._bioEntites[0].getModelId(); +}; + +SearchAliasGroup.prototype.getReactants = function () { + return this._bioEntites[0].getReactants(); +}; +SearchAliasGroup.prototype.getProducts = function () { + return this._bioEntites[0].getProducts(); +}; +SearchAliasGroup.prototype.getModifiers = function () { + return this._bioEntites[0].getModifiers(); +}; + +SearchAliasGroup.prototype.getFullName = function () { + return this.getMergedParameterByFunction("getFullName"); +}; + +SearchAliasGroup.prototype.getReactionId = function () { + return this.getMergedParameterByFunction("getReactionId"); +}; +SearchAliasGroup.prototype.getLinkedSubmodelId = function () { + return this.getMergedParameterByFunction("getLinkedSubmodelId"); +}; +SearchAliasGroup.prototype.getSymbol = function () { + return this.getMergedParameterByFunction("getSymbol"); +}; +SearchAliasGroup.prototype.getAbbreviation = function () { + return this.getMergedParameterByFunction("getAbbreviation"); +}; +SearchAliasGroup.prototype.getFormula = function () { + return this.getMergedParameterByFunction("getFormula"); +}; +SearchAliasGroup.prototype.getMechanicalConfidenceScore = function () { + return this.getMergedParameterByFunction("getMechanicalConfidenceScore"); +}; +SearchAliasGroup.prototype.getLowerBound = function () { + return this.getMergedParameterByFunction("getLowerBound"); +}; +SearchAliasGroup.prototype.getUpperBound = function () { + return this.getMergedParameterByFunction("getUpperBound"); +}; +SearchAliasGroup.prototype.getGeneProteinReaction = function () { + return this.getMergedParameterByFunction("getGeneProteinReaction"); +}; +SearchAliasGroup.prototype.getSubsystem = function () { + return this.getMergedParameterByFunction("getSubsystem"); +}; +SearchAliasGroup.prototype.getDescription = function () { + return this.getMergedParameterByFunction("getDescription"); +}; +SearchAliasGroup.prototype.getCharge = function () { + return this.getMergedParameterByFunction("getCharge"); +}; +SearchAliasGroup.prototype.getSynonyms = function () { + return this.getIntersectionListByFunction("getSynonyms"); +}; +SearchAliasGroup.prototype.getFormerSymbols = function () { + return this.getIntersectionListByFunction("getFormerSymbols"); +}; + +SearchAliasGroup.prototype.getReferences = function () { + return this.getIntersectionListByFunction("getReferences"); +}; + +SearchAliasGroup.prototype.getOther = function (param) { + if (param === "modifications") { + return this.getIntersectionListByFunction(function (alias) { + return alias.getOther(param) + }); + } else { + throw new Error("Don't now how to handle: " + param); + } +}; + +SearchAliasGroup.prototype.getMergedParameterByFunction = function (functionName) { + var bioEntities = this.getBioEntities(); + var result = bioEntities[0][functionName](); + for (var i = 1; i < bioEntities.length; i++) { + var newEntry = bioEntities[i][functionName](); + if (newEntry !== result) { + result = "Value different among merged elements"; + } + } + return result; +}; + +SearchAliasGroup.prototype.getIntersectionListByFunction = function (functionName) { + var bioEntities = this.getBioEntities(); + var result; + if (typeof functionName === "function") { + result = functionName(bioEntities[0]); + } else { + result = bioEntities[0][functionName](); + } + for (var i = 1; i < bioEntities.length; i++) { + var newList; + if (typeof functionName === "function") { + newList = functionName(bioEntities[i]); + } else { + newList = bioEntities[0][functionName](); + } + //intersection of two arrays + result = result.filter(function (n) { + return newList.indexOf(n) !== -1; + }); + } + return result; +}; + + +module.exports = SearchAliasGroup; diff --git a/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js b/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js index 3256bf80c97c09c0e00f8d29e764fb2948357b76..915480fce82e8b40214c74172748461598a4fe89 100644 --- a/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js +++ b/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js @@ -11,6 +11,8 @@ var Alias = require('../data/Alias'); var IdentifiedElement = require('../data/IdentifiedElement'); var InvalidArgumentException = require('../../InvalidArgumentError'); var Reaction = require('../data/Reaction'); +var SearchBioEntityGroup = require('../data/SearchBioEntityGroup'); + var ServerConnector = require('../../ServerConnector'); @@ -44,21 +46,35 @@ SearchDbOverlay.prototype.getElementsByQuery = function (query) { var model = self.getMap().getSubmapById(elements[0].getModelId()).getModel(); promises.push(model.getByIdentifiedElement(elements[i], true)); } - return Promise.all(promises).then(function (fullElements) { + return Promise.all(promises).then(function (elements) { var result = []; var iconCounter = 1; - for (var i = 0; i < fullElements.length; i++) { - var element = fullElements[i]; - var icon; - if (element instanceof Alias) { - icon = self.getIcon(queryId, iconCounter++); - } else if (!(element instanceof Reaction)) { - throw new Error("Unknown element type: " + element.getType()); + var groups = []; + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + var alreadyExists = false; + var group; + for (var j = 0; j < groups.length; j++) { + group = groups[j]; + if (group.bioEntityMatch(element)) { + alreadyExists = true; + group.addBioEntity(element); + } + } + + if (!alreadyExists) { + var icon; + if (element instanceof Alias) { + icon = self.getIcon(queryId, iconCounter++) + } + group = new SearchBioEntityGroup(element); + group.setIcon(icon); + groups.push(group); + result.push({ + element: group, + icon: icon + }); } - result.push({ - element: element, - icon: icon - }); } return result; }); @@ -236,27 +252,50 @@ SearchDbOverlay.prototype.searchByTarget = function (element) { SearchDbOverlay.prototype.getIdentifiedElements = function () { var self = this; + var queries = self.getQueries(); + var result = []; - return new Promise(function (resolve) { - var queries = self.getQueries(); - var result = []; - for (var i = 0; i < queries.length; i++) { - var query = queries[i]; - var elements = self._elementsByQuery[query]; - + return Promise.each(queries, function (query, index) { + var identifiedElements = self._elementsByQuery[query]; + return self.getMap().fetchIdentifiedElements(identifiedElements).then(function (elements) { var iconCounter = 1; - for (var j = 0; j < elements.length; j++) { - var element = elements[j]; + var groups = []; + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + var alreadyExists = false; + var icon = null; + var group; + for (var j = 0; j < groups.length; j++) { + group = groups[j]; + if (group.bioEntityMatch(element)) { + alreadyExists = true; + group.addBioEntity(element); + icon = group.getIcon(); + } + } + + if (!alreadyExists) { + if (element instanceof Alias) { + icon = self.getIcon(index, iconCounter++) + } + group = new SearchBioEntityGroup(element); + group.setIcon(icon); + groups.push(group); + + } var ie = new IdentifiedElement(element); - if (element.getType() === "ALIAS") { - ie.setIcon(self.getIcon(i, iconCounter++)); - } else if (element.getType() !== "REACTION") { - throw new Error("Unknown element type: " + element.getType()); + if (element instanceof Alias) { + ie.setIcon(icon); + } else if (!(element instanceof Reaction)) { + throw new Error("Unknown element type: " + ie.getType()); } result.push(ie); + } - } - resolve(result); + }); + + }).then(function () { + return result; }); }; diff --git a/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js b/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js index 5d3aa3a65bb5bb07828a255af7625f7770079c10..bfa7e4381fcdb56a319461502b4f00bb7169fe96 100644 --- a/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js +++ b/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js @@ -136,6 +136,25 @@ describe('GuiUtils', function () { alias: alias }).innerHTML.indexOf("Full name") === -1); }); + + it('onclick function', function () { + var map = helper.createCustomMap(); + helper.createSearchDbOverlay(map); + + var guiUtils = new GuiUtils(); + guiUtils.setMap(map); + var alias = helper.createAlias(map); + + alias.setFullName("xxx"); + var htmlElement = guiUtils.createAliasElement({ + alias: alias, + icon: "empty.png" + }); + + var img = $("img", htmlElement)[0]; + + return img.onclick(); + }); }); describe('createLink', function () { diff --git a/frontend-js/src/test/js/map/AbstractCustomMap-test.js b/frontend-js/src/test/js/map/AbstractCustomMap-test.js index 4f2c4d282f246c559071e49a2267fa64ce1f6a94..1b76576dc5f6d32723a0c5b7602c09817b8a7828 100644 --- a/frontend-js/src/test/js/map/AbstractCustomMap-test.js +++ b/frontend-js/src/test/js/map/AbstractCustomMap-test.js @@ -324,30 +324,42 @@ describe('AbstractCustomMap', function () { assert.ok(map.isDebug()); }); - it("fitBounds", function () { - var map = helper.createCustomMap(); - var alias = helper.createAlias(map); - var ie = new IdentifiedElement(alias); - var marker = new AliasMarker({ - map: map, - element: ie - }); - var surface = new AliasSurface({ - map: map, - alias: alias, - gmapObj: new google.maps.Rectangle({ - map: map.getGoogleMap(), - bounds: new google.maps.LatLngBounds(new google.maps.LatLng(0, 0), new google.maps.LatLng(0.5, 1)) - }) + describe("fitBounds", function () { + it("surface", function () { + var map = helper.createCustomMap(); + var alias = helper.createAlias(map); + var ie = new IdentifiedElement(alias); + var marker = new AliasMarker({ + map: map, + element: ie + }); + var surface = new AliasSurface({ + map: map, + alias: alias, + gmapObj: new google.maps.Rectangle({ + map: map.getGoogleMap(), + bounds: new google.maps.LatLngBounds(new google.maps.LatLng(0, 0), new google.maps.LatLng(0.5, 1)) + }) + }); + + var markers = [marker, surface]; + return marker.init().then(function () { + + var center = map.getGoogleMap().getCenter(); + map.fitBounds(markers); + var center2 = map.getGoogleMap().getCenter(); + assert.ok(center.lat() !== center2.lat() || center.lng() !== center2.lng()); + }); }); - - var markers = [marker, surface]; - return marker.init().then(function () { - + it("reaction", function () { + var map = helper.createCustomMap(); + var reaction = helper.createReaction(map); var center = map.getGoogleMap().getCenter(); - map.fitBounds(markers); - var center2 = map.getGoogleMap().getCenter(); - assert.ok(center.lat() !== center2.lat() || center.lng() !== center2.lng()); + return map.fitBounds([reaction]).then(function () { + + var center2 = map.getGoogleMap().getCenter(); + assert.ok(center.lat() !== center2.lat() || center.lng() !== center2.lng()); + }) }); }); diff --git a/frontend-js/src/test/js/map/data/SearchBioEntityGroup-test.js b/frontend-js/src/test/js/map/data/SearchBioEntityGroup-test.js new file mode 100644 index 0000000000000000000000000000000000000000..64efc9319e55979fb4df18bfbb12d8697c556e18 --- /dev/null +++ b/frontend-js/src/test/js/map/data/SearchBioEntityGroup-test.js @@ -0,0 +1,138 @@ +"use strict"; + +require("../../mocha-config"); + +var Alias = require('../../../../main/js/map/data/Alias'); +var SearchBioEntityGroup = require('../../../../main/js/map/data/SearchBioEntityGroup'); + + +var chai = require('chai'); +var assert = chai.assert; +var logger = require('../../logger'); + +describe('SearchBioEntityGroup', function () { + beforeEach(function () { + logger.flushBuffer(); + }); + + describe("constructor", function () { + it("with alias", function () { + var alias = helper.createAlias(); + var group = new SearchBioEntityGroup(alias); + assert.ok(group); + assert.equal(logger.getWarnings().length, 0); + assert.ok(group.bioEntityMatch(alias)); + }); + it("with reaction", function () { + var reaction = helper.createReaction(); + var group = new SearchBioEntityGroup(reaction); + assert.ok(group); + assert.equal(logger.getWarnings().length, 0); + assert.ok(group.bioEntityMatch(reaction)); + }); + it("with invalid", function () { + try { + new SearchBioEntityGroup({}); + assert.ok(false, "Error expected"); + } catch (e) { + assert.equal(e.message.indexOf("Error expected"), -1) + } + }); + + }); + describe("bioEntityComparator", function () { + it("equal", function () { + var map = helper.createCustomMap(); + var alias1 = helper.createAlias(map); + var alias2 = helper.createAlias(map); + var group = new SearchBioEntityGroup(alias1); + assert.ok(group.bioEntityComparator(alias1, alias2) === 0); + }); + it("different name", function () { + var map = helper.createCustomMap(); + var alias1 = helper.createAlias(map); + var alias2 = helper.createAlias(map); + alias2.setName("different name"); + var group = new SearchBioEntityGroup(alias1); + assert.ok(group.bioEntityComparator(alias1, alias2) !== 0); + }); + it("different type", function () { + var map = helper.createCustomMap(); + var alias1 = helper.createAlias(map); + var alias2 = helper.createAlias(map); + alias2.setType("different type"); + var group = new SearchBioEntityGroup(alias1); + assert.ok(group.bioEntityComparator(alias1, alias2) !== 0); + }); + it("different state", function () { + var map = helper.createCustomMap(); + var alias1 = helper.createAlias(map); + var alias2 = helper.createAlias(map); + var otherData = {structuralState: "different state"}; + alias2.setOther(otherData); + var group = new SearchBioEntityGroup(alias1); + assert.ok(group.bioEntityComparator(alias1, alias2) !== 0); + }); + it("different modifications", function () { + var map = helper.createCustomMap(); + var alias1 = helper.createAlias(map); + var alias2 = helper.createAlias(map); + var otherData = {modifications: [{"name": "S250", "state": "PHOSPHORYLATED"}]}; + alias2.setOther(otherData); + var group = new SearchBioEntityGroup(alias1); + assert.ok(group.bioEntityComparator(alias1, alias2) !== 0); + }); + it("different class", function () { + var map = helper.createCustomMap(); + var alias = helper.createAlias(map); + var reaction = helper.createReaction(map); + var group = new SearchBioEntityGroup(alias); + assert.ok(group.bioEntityComparator(alias, reaction) !== 0); + }); + + it("different map", function () { + var map = helper.createCustomMap(); + var alias1 = helper.createAlias(map); + var alias2 = helper.createAlias(map); + alias2.setModelId(-1); + var group = new SearchBioEntityGroup(alias1); + assert.ok(group.bioEntityComparator(alias1, alias2) !== 0); + }); + + it("different compartment", function () { + var map = helper.createCustomMap(); + var alias1 = helper.createAlias(map); + var alias2 = helper.createAlias(map); + alias2.setCompartmentId(-3); + var group = new SearchBioEntityGroup(alias1); + assert.ok(group.bioEntityComparator(alias1, alias2) !== 0); + }); + + + it("different reactions", function () { + var map = helper.createCustomMap(); + var reaction1 = helper.createReaction(map); + var reaction2 = helper.createReaction(map); + var group = new SearchBioEntityGroup(reaction1); + assert.ok(group.bioEntityComparator(reaction1, reaction2) !== 0); + }); + }); + + it("addBioEntity", function () { + var map = helper.createCustomMap(); + var alias1 = helper.createAlias(map); + var alias2 = helper.createAlias(map); + var group = new SearchBioEntityGroup(alias1); + group.addBioEntity(alias2); + assert.equal(2, group.getBioEntities().length); + }); + + it("setIcon", function () { + var map = helper.createCustomMap(); + var alias1 = helper.createAlias(map); + var group = new SearchBioEntityGroup(alias1); + group.setIcon("icon.png"); + assert.equal("icon.png", group.getIcon()); + }); + +});