diff --git a/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js b/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js index f844f3767166cc043805a240964e687278b26a39..68c15f0929562f79e611c9f576ee69f54d96edf6 100644 --- a/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js +++ b/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js @@ -3,6 +3,7 @@ /* exported logger */ var logger = require('../../logger'); +var Functions = require('../../Functions'); var Promise = require("bluebird"); @@ -11,6 +12,7 @@ var Alias = require('../data/Alias'); var ConfigurationType = require('../../ConfigurationType'); var IdentifiedElement = require('../data/IdentifiedElement'); var InvalidArgumentException = require('../../InvalidArgumentError'); +var Point = require('../canvas/Point'); var Reaction = require('../data/Reaction'); var SearchBioEntityGroup = require('../data/SearchBioEntityGroup'); @@ -92,14 +94,45 @@ SearchDbOverlay.prototype.getElementsByQuery = function (query) { }); }; + +/** + * + * @param {Point} coordinates + * @param {IdentifiedElement} compartment + * @param {number} maxDistance + * @returns {Promise} + * @private + */ +SearchDbOverlay.prototype._returnCompartmentIfClickOnBorder = function (coordinates, compartment, maxDistance) { + var model = this.getMap().getSubmapById(compartment.getModelId()).getModel(); + + return model.getByIdentifiedElement(compartment).then(function (result) { + var p1 = new Point(result.getX(), result.getY()); + var p2 = new Point(result.getX() + result.getWidth(), result.getY()); + var p3 = new Point(result.getX() + result.getWidth(), result.getY() + result.getHeight()); + var p4 = new Point(result.getX(), result.getY() + result.getHeight()); + var distance = Functions.distance(coordinates, {start: p1, end: p2}); + distance = Math.min(distance, Functions.distance(coordinates, {start: p2, end: p3})); + distance = Math.min(distance, Functions.distance(coordinates, {start: p3, end: p4})); + distance = Math.min(distance, Functions.distance(coordinates, {start: p4, end: p1})); + + if (maxDistance>distance) { + return compartment; + } else { + return undefined; + } + }); +}; + /** * * @param {IdentifiedElement} identifiedElement * @param {number} zoomLevel + * @param {Point} coordinates * @returns {Promise} * @private */ -SearchDbOverlay.prototype._getFirstVisibleParentOrObject = function (identifiedElement, zoomLevel) { +SearchDbOverlay.prototype._getFirstVisibleParentOrObject = function (identifiedElement, zoomLevel, coordinates) { if (identifiedElement === undefined) { return Promise.resolve(); } @@ -110,7 +143,8 @@ SearchDbOverlay.prototype._getFirstVisibleParentOrObject = function (identifiedE if (fullElement instanceof Alias) { //transparent compartments shouldn't be clickable if (fullElement.getTransparencyLevel() <= zoomLevel && fullElement.getType() === "Compartment") { - return undefined; + var maxDistance = self.computeMaxDistance(model, zoomLevel); + return self._returnCompartmentIfClickOnBorder(coordinates, identifiedElement, maxDistance); } } return identifiedElement; @@ -129,7 +163,7 @@ SearchDbOverlay.prototype._getFirstVisibleParentOrObject = function (identifiedE type: "ALIAS", modelId: identifiedElement.getModelId() }); - return self._getFirstVisibleParentOrObject(parent, zoomLevel); + return self._getFirstVisibleParentOrObject(parent, zoomLevel, coordinates); } else { logger.warn("Cannot find visible parent for object. (zoomLevel=" + zoomLevel + ")"); logger.warn(fullElement); @@ -155,6 +189,35 @@ SearchDbOverlay.prototype.computeMaxDistance = function (model, zoom) { return distance; }; +/** + * + * @param {Point} coordinates + * @param {number} zoom + * @param {MapModel} model + * @param {number} maxDistance + * @returns {PromiseLike<T | never> | Promise<T | never>} + */ +SearchDbOverlay.prototype.findCompartmentByCoordinates = function (coordinates, zoom, model, maxDistance) { + var self = this; + return ServerConnector.getClosestElementsByCoordinates({ + modelId: model.getId(), + coordinates: coordinates, + count: 1, + type: ["Compartment"] + }).then(function (elements) { + var nestedOverlay = "Pathways and compartments"; + if (elements.length === 0) { + return undefined; + } else { + if (self.getMap().getBackgroundDataOverlay().getName() === nestedOverlay) { + return self._getFirstVisibleParentOrObject(elements[0], zoom - model.getMinZoom(), coordinates); + } else { + return self._returnCompartmentIfClickOnBorder(coordinates, elements[0], maxDistance); + } + } + }); +}; + /** * * @param {Object} params @@ -201,7 +264,7 @@ SearchDbOverlay.prototype.searchByCoordinates = function (params) { return undefined; } else { if (self.getMap().getBackgroundDataOverlay().getName() === nestedOverlay) { - return self._getFirstVisibleParentOrObject(elements[0], zoom - model.getMinZoom()); + return self._getFirstVisibleParentOrObject(elements[0], zoom - model.getMinZoom(), coordinates); } else { return elements[0]; } @@ -234,23 +297,7 @@ SearchDbOverlay.prototype.searchByCoordinates = function (params) { if (distance <= maxDistance) { self._elementsByQuery[query] = searchResult; } else { - return ServerConnector.getClosestElementsByCoordinates({ - modelId: modelId, - coordinates: coordinates, - count: 1, - type: ["Compartment"] - }).then(function (elements) { - var nestedOverlay = "Pathways and compartments"; - if (elements.length === 0) { - return undefined; - } else { - if (self.getMap().getBackgroundDataOverlay().getName() === nestedOverlay) { - return self._getFirstVisibleParentOrObject(elements[0], zoom - model.getMinZoom()); - } else { - return undefined; - } - } - }).then(function (visibleObject) { + return self.findCompartmentByCoordinates(coordinates, zoom, model, maxDistance).then(function (visibleObject) { if (visibleObject !== undefined) { self._elementsByQuery[query] = [visibleObject]; } else { diff --git a/frontend-js/src/test/js/helper.js b/frontend-js/src/test/js/helper.js index 7d7fb45b1ff4f1023dcc6f4e2f5905a3121d025e..ab4c42c742d31a8ddbdfe2f3cfc6cb7af7cb7a2b 100644 --- a/frontend-js/src/test/js/helper.js +++ b/frontend-js/src/test/js/helper.js @@ -462,7 +462,7 @@ Helper.prototype.createAbstractCustomMap = function () { /** * - * @param project + * @param {Project} [project] * @returns {CustomMap} */ Helper.prototype.createCustomMap = function (project) { diff --git a/frontend-js/src/test/js/map/overlay/SearchDbOverlay-test.js b/frontend-js/src/test/js/map/overlay/SearchDbOverlay-test.js index 7eeba0c3e1684793abc33550b6b54862da6b8398..1ff3665b028863ea6d0ebbcbc82ee0437ef61eec 100644 --- a/frontend-js/src/test/js/map/overlay/SearchDbOverlay-test.js +++ b/frontend-js/src/test/js/map/overlay/SearchDbOverlay-test.js @@ -1,4 +1,4 @@ -t"use strict"; +"use strict"; var logger = require('../../logger'); require("../../mocha-config"); @@ -153,6 +153,28 @@ describe('SearchDbOverlay', function () { }); }); + it("on compartment border", function () { + helper.setUrl("http://test/?id=complex_model_with_submaps"); + var map; + return ServerConnector.getProject().then(function (project) { + map = helper.createCustomMap(project); + return map.openDataOverlay(14961); + }).then(function () { + + var searchDb = helper.createSearchDbOverlay(map); + + var searchParams = { + modelId: map.getModel().getId(), + coordinates: new Point(104.36, 182.81), + zoom: 4 + }; + return searchDb.searchByCoordinates(searchParams); + }).then(function (result) { + assert.equal(result.length, 1); + }); + + }); + it("on hidden nested object", function () { return ServerConnector.getProject().then(function (project) { @@ -242,4 +264,5 @@ describe('SearchDbOverlay', function () { }); -}); +}) +; diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/16728/bioEntities.search/coordinates=104.36,182.81&count=1&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/16728/bioEntities.search/coordinates=104.36,182.81&count=1&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000000000000000000000000000000000..efcec7f8da674b402d62d9b674c5bfc256cc12ea --- /dev/null +++ b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/16728/bioEntities.search/coordinates=104.36,182.81&count=1&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"id":345331,"modelId":16728,"type":"ALIAS"}] \ No newline at end of file diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/16728/bioEntities.search/coordinates=104.36,182.81&count=1&type=Compartment&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/16728/bioEntities.search/coordinates=104.36,182.81&count=1&type=Compartment&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000000000000000000000000000000000..46a291bd26e929ef7376e3ca227948f78c85d741 --- /dev/null +++ b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/16728/bioEntities.search/coordinates=104.36,182.81&count=1&type=Compartment&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"id":345323,"modelId":16728,"type":"ALIAS"}] \ No newline at end of file diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345323&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345323&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000000000000000000000000000000000..392b44d0f9c421325d6eec0f73a72fb35c40b658 --- /dev/null +++ b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345323&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"bounds":{"height":142.0,"width":144.0,"x":35.0,"y":45.0},"id":345323,"linkedSubmodel":null,"modelId":16728}] \ No newline at end of file diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/id=345323&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/id=345323&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000000000000000000000000000000000..10efe849d6ce6ecef22eeb1cfedfc94ef7ec6d99 --- /dev/null +++ b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/id=345323&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"abbreviation":null,"boundaryCondition":null,"bounds":{"height":142.0,"width":144.0,"x":35.0,"y":45.0},"compartmentId":null,"complexId":null,"constant":null,"elementId":"ca1","formerSymbols":[],"formula":null,"fullName":null,"hierarchyVisibilityLevel":"0","id":345323,"initialAmount":null,"initialConcentration":null,"linkedSubmodel":null,"modelId":16728,"name":"c1","notes":"","other":{"modifications":[],"structuralState":null,"structures":{}},"references":[],"symbol":null,"synonyms":[],"transparencyLevel":"2","type":"Compartment"}] \ No newline at end of file