From fe52bed04d064a2b85a9ebdef9b1c3a397a8063c Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Fri, 6 Jan 2017 19:15:55 +0100 Subject: [PATCH] first approach to search Db Ovelay clicking on map access appropriate elements vi api --- frontend-js/src/main/js/ServerConnector.js | 70 +------- .../src/main/js/map/AbstractCustomMap.js | 10 +- frontend-js/src/main/js/map/CustomMap.js | 159 +++++++++--------- .../src/main/js/map/data/IdentifiedElement.js | 33 ++-- frontend-js/src/main/js/map/data/MapModel.js | 3 +- frontend-js/src/main/js/map/data/Reaction.js | 18 +- .../main/js/map/overlay/CommentDbOverlay.js | 17 +- .../main/js/map/overlay/OverlayCollection.js | 30 +++- .../main/js/map/overlay/SearchDbOverlay.js | 106 ++++++++++++ frontend-js/src/main/js/minerva.js | 3 + .../src/test/js/ServerConnector-mock.js | 12 -- frontend-js/src/test/js/google-map-mock.js | 40 ++++- frontend-js/src/test/js/helper.js | 11 ++ frontend-js/src/test/js/map/CustomMap-test.js | 31 +++- frontend-js/src/test/js/minerva-test.js | 18 ++ ...lse&projectId=sample&token=MOCK_TOKEN_ID&} | 0 ...102&projectId=sample&token=MOCK_TOKEN_ID&} | 0 ...5781&projectId=sample&token=MOCK_TOKEN_ID& | 1 + ...5781&projectId=sample&token=MOCK_TOKEN_ID& | 1 + ...9180&projectId=sample&token=MOCK_TOKEN_ID& | 1 + ...9173&projectId=sample&token=MOCK_TOKEN_ID& | 1 + ...3515&projectId=sample&token=MOCK_TOKEN_ID& | 1 + 22 files changed, 375 insertions(+), 191 deletions(-) create mode 100644 frontend-js/src/main/js/map/overlay/SearchDbOverlay.js rename frontend-js/testFiles/apiCalls/comment/addComment/{content=&coordinates=2,12&elementId=&elementType=POINT&email=&modelId=102&name=&pinned=false&projectId=sample&token=MOCK_TOKEN_ID& => content=&coordinates=2.00,12.00&elementId=&elementType=POINT&email=&modelId=102&name=&pinned=false&projectId=sample&token=MOCK_TOKEN_ID&} (100%) rename frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/{coordinates=2,12&modelId=102&projectId=sample&token=MOCK_TOKEN_ID& => coordinates=2.00,12.00&modelId=102&projectId=sample&token=MOCK_TOKEN_ID&} (100%) create mode 100644 frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=26547.33,39419.29&count=1&modelId=15781&projectId=sample&token=MOCK_TOKEN_ID& create mode 100644 frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=26547.33,40201.07&count=1&modelId=15781&projectId=sample&token=MOCK_TOKEN_ID& create mode 100644 frontend-js/testFiles/apiCalls/project/getElements/columns=&id=329156,329162,329174,329180&projectId=sample&token=MOCK_TOKEN_ID& create mode 100644 frontend-js/testFiles/apiCalls/project/getElements/columns=id,bounds,modelId&id=329173&projectId=sample&token=MOCK_TOKEN_ID& create mode 100644 frontend-js/testFiles/apiCalls/project/getReactions/columns=&id=153515&projectId=sample&token=MOCK_TOKEN_ID& diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js index 70b703de56..1de30ae567 100644 --- a/frontend-js/src/main/js/ServerConnector.js +++ b/frontend-js/src/main/js/ServerConnector.js @@ -43,13 +43,6 @@ ServerConnector.formIdentifier = "_gmapForm"; ServerConnector._customMap = null; -/** - * Sets search query that will be handled by server. - */ -ServerConnector.setSearchQuery = function(value) { - document.getElementById(ServerConnector.formIdentifier + ':mapParam').value = "" + value; -}; - /** * Sets data mining query that will be handled by server. */ @@ -153,11 +146,6 @@ ServerConnector.updateOverlayCollection = function(overlayName, data, fitBounds) } }; -/** - * Name of the overlay for 'search' overlay. - */ -ServerConnector.SEARCH_OVERLAY_NAME = 'search'; - /** * Name of the overlay for 'data mining' overlay. */ @@ -178,30 +166,6 @@ ServerConnector.CHEMICAL_OVERLAY_NAME = 'chemical'; */ ServerConnector.MI_RNA_OVERLAY_NAME = 'mirna'; -/** - * Register 'search' overlay on the server. - */ -ServerConnector.registerSearchOverlay = function() { - _registerSearchOverlayCollection([ { - name : "overlayName", - value : ServerConnector.SEARCH_OVERLAY_NAME, - } ]); -}; - -/** - * Sends request to the server to refresh data in 'search' overlay. - */ -ServerConnector.refreshSearchOverlay = function() { - _refreshSearchOverlayCollection(); -}; - -/** - * Clear data related to 'search' overlay.. - */ -ServerConnector.clearSearchOverlay = function() { - _clearSearchOverlayCollection(); -}; - /** * Register 'data mining' overlay on the server. */ @@ -351,15 +315,6 @@ ServerConnector.clearMiRnaOverlay = function() { _clearMiRnaOverlayCollection(); }; -/** - * Define pack of methods for 'search' overlay. - */ -ServerConnector._overlayMethods[ServerConnector.SEARCH_OVERLAY_NAME] = { - initFunction : ServerConnector.registerSearchOverlay, - refreshFunction : ServerConnector.refreshSearchOverlay, - clearFunction : ServerConnector.clearSearchOverlay, -}; - /** * Define pack of methods for 'data minig' overlay. */ @@ -495,19 +450,6 @@ ServerConnector.addReactions = function(jsonReactions) { this.getCustomMap().addReactions(jsonReactions); }; -ServerConnector.searchByCoord = function(modelId, latLngCoordinates) { - _searchByCoord([ { - name : 'submodelId', - value : modelId - }, { - name : 'latCoord', - value : latLngCoordinates.lat() - }, { - name : 'lngCoord', - value : latLngCoordinates.lng() - } ]); -}; - ServerConnector.sendReferenceGenomeDetailRequest = function(type, version) { logger.debug("Send request", type, version); _sendReferenceGenomeDetailRequest([ { @@ -726,7 +668,7 @@ ServerConnector.idsToString = function (ids) { }; ServerConnector.pointToString = function (point) { - return point.x+","+point.y; + return point.x.toFixed(2)+","+point.y.toFixed(2); }; ServerConnector.columnsToString = function (columns) { @@ -781,13 +723,15 @@ ServerConnector.getClosestElementsByCoordinatesUrl = function(params) { var projectId = params.projectId; var modelId = params.modelId; var token = params.token; + var count = params.count; return this.getApiUrl({type:"project", method:"getClosestElementsByCoordinates", params: { projectId: projectId, coordinates: coordinates, - modelId: modelId, + modelId: modelId, + count: count, token: token}, }); }; @@ -1020,13 +964,13 @@ ServerConnector.getSessionData = function(project) { ServerConnector.getClosestElementsByCoordinates = function(params) { var self = this; - var projectId; return new Promise(function(resolve, reject) { return self.getProjectId(params.projectId).then(function(result) { - projectId = result; + params.projectId = result; return self.getToken(); }).then(function(token) { - return self.readFile(self.getClosestElementsByCoordinatesUrl({projectId:projectId, token:token, modelId:params.modelId, coordinates: params.coordinates})); + params.token = token; + return self.readFile(self.getClosestElementsByCoordinatesUrl(params)); }).then(function(content) { var array=JSON.parse(content); var result = []; diff --git a/frontend-js/src/main/js/map/AbstractCustomMap.js b/frontend-js/src/main/js/map/AbstractCustomMap.js index 5263499926..7a70a061cc 100644 --- a/frontend-js/src/main/js/map/AbstractCustomMap.js +++ b/frontend-js/src/main/js/map/AbstractCustomMap.js @@ -313,7 +313,11 @@ AbstractCustomMap.prototype.registerMapClickEvents = function() { // search event google.maps.event.addListener(this.getGoogleMap(), 'click', function(mouseEvent) { - ServerConnector.searchByCoord(self.getId(), mouseEvent.latLng); + var point = self.fromLatLngToPoint(mouseEvent.latLng); + var searchDb = customMap.getOverlayByName('search'); + return searchDb.searchByCoordinates(self.getModel(), point).then(function() { + return customMap.updateOverlayCollection(searchDb, false); + }).catch(GuiConnector.alert); }); // select last clicked map @@ -685,8 +689,8 @@ AbstractCustomMap.prototype.getAliasVisibleLayoutsData = function(aliasId) { for (var i = 0; i < layoutIds.length; i++) { promises.push(this.getModel().getLayoutDataById(layoutIds[i])); } - return new Promise(function(resolve){ - return Promise.all(promises).then(function(layouts){ + return new Promise(function(resolve) { + return Promise.all(promises).then(function(layouts) { var result = []; for (var i = 0; i < layouts.length; i++) { var layout = layouts[i]; diff --git a/frontend-js/src/main/js/map/CustomMap.js b/frontend-js/src/main/js/map/CustomMap.js index 9e3d6a61b5..689281d9de 100644 --- a/frontend-js/src/main/js/map/CustomMap.js +++ b/frontend-js/src/main/js/map/CustomMap.js @@ -16,6 +16,7 @@ var PointMarker = require('./marker/PointMarker'); var ReactionMarker = require('./marker/ReactionMarker'); var ReactionOverlay = require('./overlay/ReactionOverlay'); var ReferenceGenome = require('./data/ReferenceGenome'); +var SearchDbCollection = require('./overlay/SearchDbOverlay'); var Submap = require('./Submap'); var TouchMap = require('./TouchMap'); @@ -214,7 +215,9 @@ CustomMap.prototype.refreshOverlays = function() { for ( var overlayName in this.overlayCollections) { if (this.overlayCollections.hasOwnProperty(overlayName)) { var collection = this.overlayCollections[overlayName]; - promises.push(collection.refresh()); + if (!collection instanceof SearchDbCollection) { + promises.push(collection.refresh()); + } } } return Promise.all(promises); @@ -549,25 +552,16 @@ CustomMap.prototype.refreshOverlayMarkers = function(overlay) { if (overlay.reactionMarkers.hasOwnProperty(reactionKey) && overlay.reactionMarkers[reactionKey] !== undefined && overlay.reactionMarkers[reactionKey] !== null) { var reactionOverlay = overlay.reactionMarkers[reactionKey]; - if (reactionOverlay.getReactionData() === null || reactionOverlay.getReactionData() === undefined) { - reactionOverlay.getCustomMap().getModel().getReactionById(reactionOverlay.getId()).then(function(reactionData) { - reactionOverlay.setReactionData(reactionData); - reactionOverlay.init(); - reactionOverlay.show(); - updated = true; - bounds = reactionOverlay.getBounds(); - boundsArray[reactionOverlay.getCustomMap().getId()].extend(bounds.getNorthEast()); - boundsArray[reactionOverlay.getCustomMap().getId()].extend(bounds.getSouthWest()); - }); - } else { - bounds = reactionOverlay.getBounds(); - if (!this.isMarkerOptimization()) { - reactionOverlay.hide(); - reactionOverlay.show(); - } - boundsArray[reactionOverlay.getCustomMap().getId()].extend(bounds.getNorthEast()); - boundsArray[reactionOverlay.getCustomMap().getId()].extend(bounds.getSouthWest()); + if (!reactionOverlay.isShown()) { + reactionOverlay.show(); + } + bounds = reactionOverlay.getBounds(); + if (!this.isMarkerOptimization()) { + reactionOverlay.hide(); + reactionOverlay.show(); } + boundsArray[reactionOverlay.getCustomMap().getId()].extend(bounds.getNorthEast()); + boundsArray[reactionOverlay.getCustomMap().getId()].extend(bounds.getSouthWest()); } } @@ -1356,70 +1350,75 @@ CustomMap.prototype.renderOverlayCollection = function(overlayCollection, fitBou fitBounds = overlayCollection.fitBounds; overlayCollection = overlayCollection.overlayCollection; } + + var elements; + + return overlayCollection.getIdentifiedElements().then(function(identifiedElements){ + elements = identifiedElements; + var boundsArray = []; + boundsArray[self.getId()] = new google.maps.LatLngBounds(); + for (var j = 0; j < self.submaps.length; j++) { + boundsArray[self.submaps[j].getId()] = new google.maps.LatLngBounds(); + } - var elements = overlayCollection.getIdentifiedElements(); - - var boundsArray = []; - boundsArray[this.getId()] = new google.maps.LatLngBounds(); - for (var j = 0; j < this.submaps.length; j++) { - boundsArray[this.submaps[j].getId()] = new google.maps.LatLngBounds(); - } - - var bounds; - - return Promise.each( - elements, - function(element) { - var model = self.getSubmodelById(element.modelId); - if (element.getType() === "ALIAS") { - if (overlayCollection.aliasMarkers[element.getId()] !== undefined) { - logger.warn("More than one marker in " + overlayCollection.name + " for alias " + element.getId() - + ". Skipping duplicates."); - return null; - } else { - return model.getModel().getAliasById(element.getId()).then(function(aliasData) { - var aliasMarker = new AliasMarker(element.getId(), element.icon, aliasData, model); - overlayCollection.aliasMarkers[element.getId()] = aliasMarker; - bounds = aliasMarker.getBounds(); + var bounds; + + return Promise.each( + elements, + function(element) { + var model = self.getSubmodelById(element.modelId); + if (element.getType() === "ALIAS") { + if (overlayCollection.aliasMarkers[element.getId()] !== undefined) { + logger.warn("More than one marker in " + overlayCollection.name + " for alias " + element.getId() + + ". Skipping duplicates."); + return null; + } else { + return model.getModel().getAliasById(element.getId()).then(function(aliasData) { + var aliasMarker = new AliasMarker(element.getId(), element.icon, aliasData, model); + overlayCollection.aliasMarkers[element.getId()] = aliasMarker; + bounds = aliasMarker.getBounds(); + boundsArray[element.getModelId()].extend(bounds.getNorthEast()); + boundsArray[element.getModelId()].extend(bounds.getSouthWest()); + return aliasMarker; + }); + } + } else if (element.getType() === "REACTION") { + return model.getModel().getReactionById(element.getId()).then(function(reactionData) { + var marker = null; + var icon = element.getIcon(); + + if (icon === null || icon === undefined) { + // this should happen when we visualize search data (there is + // no marker, but only flat overlay of the reaction lines) + // + marker = new ReactionOverlay(null, reactionData, model, false, element.getId()); + } else { + // when we have icon defined (for instance when it comes from + // comment) then we don't want to have overlayed reaction lines + // but icon marker + marker = new ReactionMarker(element.getId(), icon, reactionData, model); + } + marker.show(); + overlayCollection.reactionMarkers[element.getId()] = marker; + bounds = marker.getBounds(); boundsArray[element.getModelId()].extend(bounds.getNorthEast()); boundsArray[element.getModelId()].extend(bounds.getSouthWest()); - return aliasMarker; + return marker; }); - } - } else if (element.getType() === "REACTION") { - return model.getModel().getReactionById(element.getId()).then(function(reactionData) { - var marker = null; - var icon = element.getIcon(); - - if (icon === null || icon === undefined) { - // this should happen when we visualize search data (there is - // no marker, but only flat overlay of the reaction lines) - // - marker = new ReactionOverlay(null, reactionData, model, false, element.getId()); - } else { - // when we have icon defined (for instance when it comes from - // comment) then we don't want to have overlayed reaction lines - // but icon marker - marker = new ReactionMarker(element.getId(), icon, reactionData, model); - } - overlayCollection.reactionMarkers[element.getId()] = marker; - bounds = marker.getBounds(); + } else if (element.getType() === "POINT") { + var pointData = model.getModel().getPointDataByPoint(element.getPoint()); + var pointMarker = new PointMarker(pointData, element.icon, model); + overlayCollection.pointMarkers[pointData.getId()] = pointMarker; + bounds = pointMarker.getBounds(); boundsArray[element.getModelId()].extend(bounds.getNorthEast()); boundsArray[element.getModelId()].extend(bounds.getSouthWest()); - return marker; - }); - } else if (element.getType() === "POINT") { - var pointData = model.getModel().getPointDataByPoint(element.getPoint()); - var pointMarker = new PointMarker(pointData, element.icon, model); - overlayCollection.pointMarkers[pointData.getId()] = pointMarker; - bounds = pointMarker.getBounds(); - boundsArray[element.getModelId()].extend(bounds.getNorthEast()); - boundsArray[element.getModelId()].extend(bounds.getSouthWest()); - return pointMarker; - } else { - throw new Error("Unknown type of the element in overlay: " + element.type); - } - }).then(function() { + return pointMarker; + } else { + throw new Error("Unknown type of the element in overlay: " + element.type); + } + }); + }).then(function() { + for (var i = 0; i < elements.length; i++) { var element = elements[i]; var infoWindow = self.getInfoWindowForIdentifiedElement(element); @@ -1447,6 +1446,8 @@ CustomMap.prototype.renderOverlayCollection = function(overlayCollection, fitBou }); + + }; /** @@ -1646,6 +1647,10 @@ CustomMap.prototype.getOverlayDataForIdentifiedElement = function(identifiedElem }); }; +CustomMap.prototype.getOverlayByName = function(name) { + return this.overlayCollections[name]; +}; + /** * Returns {@link AbstractInfoWindow} for element identified by the parameter. * diff --git a/frontend-js/src/main/js/map/data/IdentifiedElement.js b/frontend-js/src/main/js/map/data/IdentifiedElement.js index 4b849f949b..5f4730bad2 100644 --- a/frontend-js/src/main/js/map/data/IdentifiedElement.js +++ b/frontend-js/src/main/js/map/data/IdentifiedElement.js @@ -21,15 +21,15 @@ function IdentifiedElement(javaObject) { if (javaObject instanceof Alias) { this.setId(javaObject.getId()); this.setModelId(javaObject.getModelId()); - this.type = "ALIAS"; + this.setType("ALIAS"); } else if (javaObject instanceof Reaction) { this.setId(javaObject.getId()); this.setModelId(javaObject.getModelId()); - this.type = "REACTION"; + this.setType("REACTION"); } else if (javaObject instanceof PointData) { this.setId(javaObject.getId()); this.setModelId(javaObject.getModelId()); - this.type = "POINT"; + this.setType("POINT"); } else { // identifier of the object to visualize if (javaObject.objectId === undefined) { @@ -38,19 +38,14 @@ function IdentifiedElement(javaObject) { this.setId(javaObject.objectId); } // which marker should be used to show this object - this.icon = javaObject.icon; + this.setIcon(javaObject.icon); // on which model the element is located this.setModelId(javaObject.modelId); // what kind of object we are talking about - this.type = javaObject.type; + this.setType(javaObject.type); } - if (this.type === undefined || this.type === null) { - throw new Error("Type not defined for element: " + javaObject); - } - - this.type = this.type.toUpperCase(); - if (this.type === "POINT") { + if (this.getType() === "POINT") { var tmp = this.getId(); if (tmp.indexOf("Point2D.Double") >= 0) { tmp = tmp.replace("Point2D.Double", ""); @@ -63,8 +58,8 @@ function IdentifiedElement(javaObject) { var x = parseFloat(tmp[0]).toFixed(2); var y = parseFloat(tmp[1]).toFixed(2); this._point = new google.maps.Point(x, y); - } else if (this.type !== "ALIAS" && this.type !== "REACTION") { - throw new Error("Unknown type of identified element: " + this.type); + } else if (this.getType() !== "ALIAS" && this.getType() !== "REACTION") { + throw new Error("Unknown type of identified element: " + this.getType()); } if (this.getId() === undefined || this.getId() === null) { @@ -137,6 +132,14 @@ IdentifiedElement.prototype.getType = function() { return this.type; }; +IdentifiedElement.prototype.setType = function(type) { + if (type === undefined || type === null) { + throw new Error("Type not defined"); + } + + this.type = type.toUpperCase(); +}; + /** * Returns icon that should be used for visualization. * @@ -146,4 +149,8 @@ IdentifiedElement.prototype.getIcon = function() { return this.icon; }; +IdentifiedElement.prototype.setIcon = function(icon) { + this.icon = icon; +}; + module.exports = IdentifiedElement; diff --git a/frontend-js/src/main/js/map/data/MapModel.js b/frontend-js/src/main/js/map/data/MapModel.js index 6201f0a402..c7370e2973 100644 --- a/frontend-js/src/main/js/map/data/MapModel.js +++ b/frontend-js/src/main/js/map/data/MapModel.js @@ -177,7 +177,7 @@ MapModel.prototype.getReactionById = function(id, complete) { MapModel.prototype.getCompleteReactionById = function(id) { var self = this; return new Promise(function(resolve) { - if (self._reactions[id]!==undefined && self._reactions[id].isComplete()) { + if (self._reactions[id] instanceof Reaction && self._reactions[id].isComplete()) { resolve(self._reactions[id]); } else { var result; @@ -296,7 +296,6 @@ MapModel.prototype.getMissingElements = function(elements) { } } - return new Promise(function(resolve, reject) { Promise.all([reactionPromise, aliasPromise]).then(function(values) { var result = [], i; diff --git a/frontend-js/src/main/js/map/data/Reaction.js b/frontend-js/src/main/js/map/data/Reaction.js index 8b6aae5848..395353c819 100644 --- a/frontend-js/src/main/js/map/data/Reaction.js +++ b/frontend-js/src/main/js/map/data/Reaction.js @@ -39,7 +39,7 @@ function Reaction(javaObject) { } this.setCenter(javaObject.centerPoint); this.setModelId(javaObject.modelId); - this.setCompletness(false); + this.setIsComplete(false); this.update(javaObject); } } @@ -112,12 +112,12 @@ Reaction.prototype.update = function(javaObject) { } }; -Reaction.prototype.getCompletness = function() { - return this._completness; +Reaction.prototype.isComplete = function() { + return this._complete; }; -Reaction.prototype.setCompletness = function(completness) { - this._completness = completness; +Reaction.prototype.setIsComplete = function(complete) { + this._complete = complete; }; Reaction.prototype.getReactionId = function() { @@ -144,6 +144,14 @@ Reaction.prototype.getProducts = function() { return this._products; }; +Reaction.prototype.getElements = function() { + var result = []; + result = result.concat(this.getReactants()); + result = result.concat(this.getProducts()); + result = result.concat(this.getModifiers()); + return result; +}; + Reaction.prototype.setModifiers = function(modifiers) { this._modifiers = modifiers; }; diff --git a/frontend-js/src/main/js/map/overlay/CommentDbOverlay.js b/frontend-js/src/main/js/map/overlay/CommentDbOverlay.js index 41df64f1cc..abbbec7715 100644 --- a/frontend-js/src/main/js/map/overlay/CommentDbOverlay.js +++ b/frontend-js/src/main/js/map/overlay/CommentDbOverlay.js @@ -43,14 +43,17 @@ CommentDbOverlay.prototype._getDetailArrayByIdentifiedElement = function(element CommentDbOverlay.prototype.getIdentifiedElements = function(){ - var result = []; - for (var i=0;i<this.elements.length;i++) { - //we return only elements that are pinned to the map and weren't removed - if (!this.elements[i].isRemoved()) { - result.push(this.elements[i].getIdentifiedElement()); + var self = this; + return new Promise(function(resolve){ + var result = []; + for (var i=0;i<self.elements.length;i++) { + // we return only elements that are pinned to the map and weren't removed + if (!self.elements[i].isRemoved()) { + result.push(self.elements[i].getIdentifiedElement()); + } } - } - return result; + resolve(result); + }); }; diff --git a/frontend-js/src/main/js/map/overlay/OverlayCollection.js b/frontend-js/src/main/js/map/overlay/OverlayCollection.js index c1fff1bcb6..0679d67318 100644 --- a/frontend-js/src/main/js/map/overlay/OverlayCollection.js +++ b/frontend-js/src/main/js/map/overlay/OverlayCollection.js @@ -236,8 +236,34 @@ OverlayCollection.prototype.setAllowGeneralSearch = function(allowGeneralSearch) } }; -OverlayCollection.prototype.getIdentifiedElements = function(){ - return this.elements; +OverlayCollection.prototype.getIdentifiedElements = function() { + var self = this; + return new Promise(function(resolve) { + resolve(self.elements); + }); +}; + +OverlayCollection.prototype.setIconType = function(iconType) { + return this._iconType = iconType; +}; +OverlayCollection.prototype.setIconStart = function(iconStart) { + return this._iconStart = iconStart; +}; + +OverlayCollection.IconColors = [ "red", "blue", "green", "purple", "yellow", "pink", "paleblue", "brown", "orange" ]; + +OverlayCollection.prototype.getColor = function(colorId) { + var id = colorId + this._iconStart; + id %= OverlayCollection.IconColors.length; + return OverlayCollection.IconColors[id]; +} + +OverlayCollection.prototype.getIcon = function(colorId, id) { + if (id >= 100) { + id = 1; + } + var color = this.getColor(colorId); + return "marker/" + this._iconType + "/" + this._iconType + "_" + color + "_" + id + ".png"; }; module.exports = OverlayCollection; diff --git a/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js b/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js new file mode 100644 index 0000000000..be7537e826 --- /dev/null +++ b/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js @@ -0,0 +1,106 @@ +"use strict"; + +var Promise = require("bluebird"); + +var Alias = require('../data/Alias'); +var IdentifiedElement = require('../data/IdentifiedElement'); +var OverlayCollection = require('./OverlayCollection'); + +var logger = require('../../logger'); + +function SearchDbOverlay(params) { + // call super constructor + OverlayCollection.call(this, params); + + this.setIconType("marker"); + this.setIconStart(0); + this._elementsByQuery = []; +} + +SearchDbOverlay.prototype = Object.create(OverlayCollection.prototype); +SearchDbOverlay.prototype.constructor = SearchDbOverlay; + +SearchDbOverlay.QueryType = { + SEARCH_BY_COORDINATES : "SEARCH_BY_COORDINATES", + SEARCH_BY_QUERY : "SEARCH_BY_QUERY", +}; + +function encodeQuery(type, model, arg){ + if (type === SearchDbOverlay.QueryType.SEARCH_BY_COORDINATES) { + return type + "_"+model.getId()+"_"+arg.x+","+arg.y; + } else { + throw new Error("Unknown query type: "+type); + } +} + +SearchDbOverlay.prototype.searchByCoordinates = function(model, coordinates) { + var self = this; + return new Promise(function(resolve, reject) { + var query = encodeQuery(SearchDbOverlay.QueryType.SEARCH_BY_COORDINATES, model, coordinates); + self.setQueries([query]); + + if (self._elementsByQuery[query] !== undefined) { + resolve(self._elementsByQuery[query]); + } else { + return ServerConnector.getClosestElementsByCoordinates({ + modelId:model.getId(), coordinates: coordinates, count: 1 + }).then(function(elements) { + self._elementsByQuery[query] = elements; + if (elements[0].getType()==="REACTION") { + var model = self.getMap().getSubmodelById(elements[0].getModelId()).getModel(); + return model.getReactionById(elements[0].getId(), true).then(function(reaction){ + var i=0; + var reactionElements = reaction.getElements(); + for (i=0;i<reactionElements.length;i++) { + self._elementsByQuery[query].push(new IdentifiedElement(reactionElements[i])); + } + resolve(self._elementsByQuery[query]); + }).catch(reject); + } else { + resolve(self._elementsByQuery[query]); + } + }).catch(reject); + } + }); +}; + +SearchDbOverlay.prototype.setQueries = function(queries){ + this._queries = queries; +}; + +SearchDbOverlay.prototype.getQueries = function(){ + return this._queries ; +}; + +SearchDbOverlay.prototype.getIdentifiedElements = function(){ + var self = this; + + 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]; + + var iconCounter =1; + for (var j=0;j<elements.length;j++) { + var element = elements[j]; + 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()); + } + result.push(ie); + } + } + resolve(result); + }); +}; + +SearchDbOverlay.prototype.refresh = function(){ + throw new Error("Refreshing shouldn't be called"); +}; + + +module.exports = SearchDbOverlay; diff --git a/frontend-js/src/main/js/minerva.js b/frontend-js/src/main/js/minerva.js index 3aab0b86ef..daf8c324d7 100644 --- a/frontend-js/src/main/js/minerva.js +++ b/frontend-js/src/main/js/minerva.js @@ -5,6 +5,7 @@ var functions = require('./Functions'); var CommentDbOverlay = require('./map/overlay/CommentDbOverlay'); var CustomMap = require('./map/CustomMap'); var OverlayCollection = require('./map/overlay/OverlayCollection'); +var SearchDbOverlay = require('./map/overlay/SearchDbOverlay'); var OriginalGuiConnector = require('./GuiConnector'); var OriginalServerConnector = require('./ServerConnector'); @@ -75,6 +76,8 @@ function create(params) { var collection = null; if (collectionParams.name === "comment") { collection = new CommentDbOverlay(collectionParams); + } else if (collectionParams.name === "search") { + collection = new SearchDbOverlay(collectionParams); } else { collection = new OverlayCollection(collectionParams); } diff --git a/frontend-js/src/test/js/ServerConnector-mock.js b/frontend-js/src/test/js/ServerConnector-mock.js index 0f84b28d5a..1819d39311 100644 --- a/frontend-js/src/test/js/ServerConnector-mock.js +++ b/frontend-js/src/test/js/ServerConnector-mock.js @@ -108,18 +108,6 @@ ServerConnectorMock.sendOverlayDetailDataRequest = function(overlayName, identif ServerConnectorMock.callListeners("onSendOverlayDetailDataRequest", overlayName, identifiedElement); }; -ServerConnectorMock.searchByCoord = function(modelId, latLngCoordinates) { - ServerConnectorMock.callListeners("onSearchByCoord", [ modelId, latLngCoordinates ]); -}; - -ServerConnectorMock.setCustomMap = function(customMap) { - this._customMap = customMap; -}; - -ServerConnectorMock.getCustomMap = function() { - return this._customMap; -}; - ServerConnectorMock.addOverlayCollection = function(overlay) { logger.debug("Adding overlay: " + overlay); }; diff --git a/frontend-js/src/test/js/google-map-mock.js b/frontend-js/src/test/js/google-map-mock.js index 949e0a8474..da21005981 100644 --- a/frontend-js/src/test/js/google-map-mock.js +++ b/frontend-js/src/test/js/google-map-mock.js @@ -15,12 +15,14 @@ var google = { object.addEventListener(type, fun); }, trigger : function(object, type, param) { + var promises = []; for (var i = 0; i < google.maps.event._data.length; i++) { var e = google.maps.event._data[i]; if (e.object === object && e.type === type) { - e.fun(param); + promises.push(e.fun(param)); } } + return Promise.all(promises); }, }, drawing : { @@ -61,15 +63,44 @@ var google = { }; }, LatLngBounds : function(ne, sw) { + var data = { + ne : ne, + sw : sw + }; return { getSouthWest : function() { - return sw; + return data.sw; }, getNorthEast : function() { - return ne; + return data.ne; + }, + isEmpty : function() { + return ne === sw || (data.ne.lat() === sw.lat() && data.ne.lng() === sw.lng()); }, - extend : function() { + extend : function(arg) { + if (data.sw === undefined) { + data.sw = arg; + } else { + if (arg.lng() < data.sw.lng()) { + data.sw.longitude = arg.lng(); + } + if (arg.lat() < data.sw.lat()) { + data.sw.longitude = arg.lng(); + } + } + if (data.ne === undefined) { + data.ne = arg; + } else { + if (arg.lng() > data.ne.lng()) { + data.ne.longitude = arg.lng(); + } + + if (arg.lat() > data.ne.lat()) { + data.ne.longitude = arg.lng(); + } + } }, + }; }, OverlayView : function() { @@ -97,6 +128,7 @@ var google = { }, Marker : function(options) { this.options = options; + this.position = options.position; this.getMap = function() { return this.options.map; }; diff --git a/frontend-js/src/test/js/helper.js b/frontend-js/src/test/js/helper.js index 7a61d23de1..b7001fdb64 100644 --- a/frontend-js/src/test/js/helper.js +++ b/frontend-js/src/test/js/helper.js @@ -16,6 +16,7 @@ var Model = require("../../main/js/map/data/MapModel"); var OverlayCollection = require("../../main/js/map/overlay/OverlayCollection"); var Project = require("../../main/js/map/data/Project"); var Reaction = require("../../main/js/map/data/Reaction"); +var SearchDbOverlay = require("../../main/js/map/overlay/SearchDbOverlay"); function Helper() { this.idCounter = 1000000; @@ -30,6 +31,16 @@ Helper.prototype.createCommentDbOverlay = function(map) { return result; }; +Helper.prototype.createSearchDbOverlay = function(map) { + var result = new SearchDbOverlay({ + map : map, + name : "search", + }); + return result; +}; + + + Helper.prototype.createDrugDbOverlay = function(map) { var result = this.createDbOverlay(map); result.setName('drug'); diff --git a/frontend-js/src/test/js/map/CustomMap-test.js b/frontend-js/src/test/js/map/CustomMap-test.js index c7d46c095a..3eebf279e5 100644 --- a/frontend-js/src/test/js/map/CustomMap-test.js +++ b/frontend-js/src/test/js/map/CustomMap-test.js @@ -467,18 +467,43 @@ describe('CustomMap', function() { assert.equal(map.getId(), map.getActiveSubmapId()); }); + it("left click on map", function() { var map = helper.createCustomMap(); - + map.getModel().setId(15781); + + var searchOverlay = helper.createSearchDbOverlay(map); + var mev = { stop : null, latLng : new google.maps.LatLng(40.0, -90.0) }; assert.notOk(map.getActiveSubmapId()); - google.maps.event.trigger(map.getGoogleMap(), 'click', mev); - assert.equal(map.getId(), map.getActiveSubmapId()); + return google.maps.event.trigger(map.getGoogleMap(), 'click', mev).then(function(){ + assert.equal(map.getId(), map.getActiveSubmapId()); + assert.ok(searchOverlay.aliasMarkers[329173]); + }); + }); + it("left click on reaction", function() { + var map = helper.createCustomMap(); + map.getModel().setId(15781); + + var searchOverlay = helper.createSearchDbOverlay(map); + + var mev = { + stop : null, + latLng : new google.maps.LatLng(42.0, -90.0) + }; + + assert.notOk(map.getActiveSubmapId()); + return google.maps.event.trigger(map.getGoogleMap(), 'click', mev).then(function(){ + assert.equal(map.getId(), map.getActiveSubmapId()); + assert.ok(searchOverlay.reactionMarkers[153515]); + assert.ok(searchOverlay.reactionMarkers[153515].isShown()); + assert.ok(searchOverlay.aliasMarkers[329162]); + }); }); it("create polygon through drawingManager", function() { diff --git a/frontend-js/src/test/js/minerva-test.js b/frontend-js/src/test/js/minerva-test.js index f2252c102d..7dc361355f 100644 --- a/frontend-js/src/test/js/minerva-test.js +++ b/frontend-js/src/test/js/minerva-test.js @@ -126,4 +126,22 @@ describe('minerva global', function() { assert.ok(result); }); }); + + it('create with search overlay', function() { + var project = helper.createProject(); + project.getModel().setId(15781); + var map = helper.createGoogleMap(); + + var options = { + map : map, + project : project, + dataCollections : [ { + name : "search" + } ], + }; + + return minerva.create(options).then(function(result) { + assert.ok(result); + }); + }); }); diff --git a/frontend-js/testFiles/apiCalls/comment/addComment/content=&coordinates=2,12&elementId=&elementType=POINT&email=&modelId=102&name=&pinned=false&projectId=sample&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/comment/addComment/content=&coordinates=2.00,12.00&elementId=&elementType=POINT&email=&modelId=102&name=&pinned=false&projectId=sample&token=MOCK_TOKEN_ID& similarity index 100% rename from frontend-js/testFiles/apiCalls/comment/addComment/content=&coordinates=2,12&elementId=&elementType=POINT&email=&modelId=102&name=&pinned=false&projectId=sample&token=MOCK_TOKEN_ID& rename to frontend-js/testFiles/apiCalls/comment/addComment/content=&coordinates=2.00,12.00&elementId=&elementType=POINT&email=&modelId=102&name=&pinned=false&projectId=sample&token=MOCK_TOKEN_ID& diff --git a/frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=2,12&modelId=102&projectId=sample&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=2.00,12.00&modelId=102&projectId=sample&token=MOCK_TOKEN_ID& similarity index 100% rename from frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=2,12&modelId=102&projectId=sample&token=MOCK_TOKEN_ID& rename to frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=2.00,12.00&modelId=102&projectId=sample&token=MOCK_TOKEN_ID& diff --git a/frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=26547.33,39419.29&count=1&modelId=15781&projectId=sample&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=26547.33,39419.29&count=1&modelId=15781&projectId=sample&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000..189815b72b --- /dev/null +++ b/frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=26547.33,39419.29&count=1&modelId=15781&projectId=sample&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"modelId":15781,"id":153515,"type":"REACTION"}] \ No newline at end of file diff --git a/frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=26547.33,40201.07&count=1&modelId=15781&projectId=sample&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=26547.33,40201.07&count=1&modelId=15781&projectId=sample&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000..410f869e59 --- /dev/null +++ b/frontend-js/testFiles/apiCalls/project/getClosestElementsByCoordinates/coordinates=26547.33,40201.07&count=1&modelId=15781&projectId=sample&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"modelId":15781,"id":329173,"type":"ALIAS"}] \ No newline at end of file diff --git a/frontend-js/testFiles/apiCalls/project/getElements/columns=&id=329156,329162,329174,329180&projectId=sample&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/project/getElements/columns=&id=329156,329162,329174,329180&projectId=sample&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000..50f4f50347 --- /dev/null +++ b/frontend-js/testFiles/apiCalls/project/getElements/columns=&id=329156,329162,329174,329180&projectId=sample&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"formerSymbols":[],"references":[],"modelId":15781,"synonyms":[],"description":"","type":"Protein","name":"s22","bounds":{"x":918.0,"y":427.0,"width":80.0,"height":40.0},"id":329162},{"formerSymbols":[],"references":[],"modelId":15781,"synonyms":[],"description":"","type":"Protein","name":"s22","bounds":{"x":712.0,"y":384.0,"width":80.0,"height":40.0},"id":329174},{"formerSymbols":[],"references":[],"modelId":15781,"synonyms":[],"description":"","type":"Simple molecule","name":"GDP","bounds":{"x":959.0,"y":271.0,"width":70.0,"height":25.0},"id":329156},{"formerSymbols":[],"references":[],"modelId":15781,"synonyms":[],"description":"","type":"Simple molecule","name":"GTP","bounds":{"x":849.0,"y":309.0,"width":70.0,"height":25.0},"id":329180}] \ No newline at end of file diff --git a/frontend-js/testFiles/apiCalls/project/getElements/columns=id,bounds,modelId&id=329173&projectId=sample&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/project/getElements/columns=id,bounds,modelId&id=329173&projectId=sample&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000..3cd9b0d710 --- /dev/null +++ b/frontend-js/testFiles/apiCalls/project/getElements/columns=id,bounds,modelId&id=329173&projectId=sample&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"modelId":15781,"bounds":{"x":12.0,"y":6.0,"width":80.0,"height":40.0},"id":329173}] \ No newline at end of file diff --git a/frontend-js/testFiles/apiCalls/project/getReactions/columns=&id=153515&projectId=sample&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/project/getReactions/columns=&id=153515&projectId=sample&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000..35ab17dc8b --- /dev/null +++ b/frontend-js/testFiles/apiCalls/project/getReactions/columns=&id=153515&projectId=sample&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"modelId":15781,"reactants":"329174,329180","reactionId":"re26","id":153515,"type":"State transition","lines":[{"start":{"x":792.0,"y":404.0},"end":{"x":868.3333333333338,"y":377.9999999999997},"type":"START"},{"start":{"x":868.3333333333338,"y":377.9999999999997},"end":{"x":893.6666666666671,"y":378.00000000000017},"type":"MIDDLE"},{"start":{"x":884.0,"y":334.0},"end":{"x":893.6666666666671,"y":378.00000000000017},"type":"START"},{"start":{"x":931.666666666667,"y":378.0000000000009},"end":{"x":918.0,"y":447.0},"type":"END"},{"start":{"x":906.3333333333337,"y":378.00000000000045},"end":{"x":931.666666666667,"y":378.0000000000009},"type":"MIDDLE"},{"start":{"x":906.3333333333337,"y":378.00000000000045},"end":{"x":994.0,"y":296.0},"type":"END"},{"start":{"x":893.6666666666671,"y":378.00000000000017},"end":{"x":896.0000000000005,"y":378.0000000000003},"type":"MIDDLE"},{"start":{"x":906.3333333333337,"y":378.00000000000045},"end":{"x":904.0000000000005,"y":378.0000000000004},"type":"MIDDLE"}],"modifiers":"","centerPoint":{"x":900.0000000000005,"y":378.00000000000034},"products":"329162,329156"}] \ No newline at end of file -- GitLab