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());
+  });
+
+});