From a3543194f9d9d0d1dea5e86a71e6827bb4953af1 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Tue, 25 Oct 2016 15:51:34 +0200 Subject: [PATCH] issue #41, work in progress submaps are opening from link (when accessing it from coment tab in admin panel), however centering is still not handled properly --- .../mapviewer/services/view/CommentView.java | 558 +-- .../services/view/CommentViewFactory.java | 6 +- .../webapp/WEB-INF/components/map/map.xhtml | 6 + .../WEB-INF/components/map/submapPanel.xhtml | 10 +- web/src/main/webapp/admin/comments.xhtml | 4 +- web/src/main/webapp/index.xhtml | 44 +- web/src/main/webapp/resources/js/CustomMap.js | 3476 +++++++++-------- .../main/webapp/resources/js/GuiConnector.js | 604 +-- 8 files changed, 2373 insertions(+), 2335 deletions(-) diff --git a/service/src/main/java/lcsb/mapviewer/services/view/CommentView.java b/service/src/main/java/lcsb/mapviewer/services/view/CommentView.java index b9b0cc85eb..43033fde72 100644 --- a/service/src/main/java/lcsb/mapviewer/services/view/CommentView.java +++ b/service/src/main/java/lcsb/mapviewer/services/view/CommentView.java @@ -1,270 +1,288 @@ -package lcsb.mapviewer.services.view; - -import java.io.Serializable; - -import lcsb.mapviewer.model.map.Comment; - -/** - * View representation of the Comment. - * - * @author Piotr Gawron - * - */ - -public class CommentView extends AbstractView<Comment> implements Serializable { - - /** - * - */ - private static final long serialVersionUID = 1L; - - /** - * Author of the comment. - */ - private String author; - - /** - * Email of the comment. - */ - private String email; - - /** - * Content of the comment. - */ - private String content; - - /** - * Title of the comment. - */ - private String title; - - /** - * Is the comment visible on the map. - */ - private String pinned; - - /** - * Is the comment removed. - */ - private String removed; - - /** - * X coordinate on the map. - */ - private String xCoord; - - /** - * Y coordinate on the map. - */ - private String yCoord; - - /** - * Zoom level at which comment should be investigated on the map (to see - * details). - */ - private String zoom; - - /** - * Constructor that initialize the view with the data from original comment. - * - * @param comment - * data required for initialization - */ - protected CommentView(final Comment comment) { - super(comment); - } - - /** - * Default constructor. Should be used only for deserialization. - */ - protected CommentView() { - } - - /** - * @return the author - * @see #author - */ - public String getAuthor() { - return author; - } - - /** - * @param author - * the author to set - * @see #author - */ - public void setAuthor(String author) { - this.author = author; - } - - /** - * @return the email - * @see #email - */ - public String getEmail() { - return email; - } - - /** - * @param email - * the email to set - * @see #email - */ - public void setEmail(String email) { - this.email = email; - } - - /** - * @return the content - * @see #content - */ - public String getContent() { - return content; - } - - /** - * @param content - * the content to set - * @see #content - */ - public void setContent(String content) { - this.content = content; - } - - /** - * @return the title - * @see #title - */ - public String getTitle() { - return title; - } - - /** - * @param title - * the title to set - * @see #title - */ - public void setTitle(String title) { - this.title = title; - } - - /** - * @return the pinned - * @see #pinned - */ - public String getPinned() { - return pinned; - } - - /** - * @param pinned - * the pinned to set - * @see #pinned - */ - public void setPinned(String pinned) { - this.pinned = pinned; - } - - /** - * @return the removed - * @see #removed - */ - public String getRemoved() { - return removed; - } - - /** - * @param removed - * the removed to set - * @see #removed - */ - public void setRemoved(String removed) { - this.removed = removed; - } - - /** - * @return the xCoord - * @see #xCoord - */ - public String getxCoord() { - return xCoord; - } - - /** - * @param xCoord - * the xCoord to set - * @see #xCoord - */ - public void setxCoord(String xCoord) { - this.xCoord = xCoord; - } - - /** - * @return the yCoord - * @see #yCoord - */ - public String getyCoord() { - return yCoord; - } - - /** - * @param yCoord - * the yCoord to set - * @see #yCoord - */ - public void setyCoord(String yCoord) { - this.yCoord = yCoord; - } - - /** - * @return the zoom - * @see #zoom - */ - public String getZoom() { - return zoom; - } - - /** - * @param zoom - * the zoom to set - * @see #zoom - */ - public void setZoom(String zoom) { - this.zoom = zoom; - } - - /** - * @param pinned - * the pinned to set - * @see #pinned - */ - public void setPinned(final boolean pinned) { - if (pinned) { - setPinned("YES"); - } else { - setPinned("NO"); - } - } - - /** - * Sets x coordinate. - * - * @param x - * x coordinate to set - * @see #xCoord - */ - public void setxCoord(double x) { - this.xCoord = x + ""; - } - - /** - * Sets y coordinate. - * - * @param y - * y coordinate to set - * @see #yCoord - */ - public void setyCoord(double y) { - this.yCoord = y + ""; - } -}; +package lcsb.mapviewer.services.view; + +import java.io.Serializable; + +import lcsb.mapviewer.model.map.Comment; + +/** + * View representation of the Comment. + * + * @author Piotr Gawron + * + */ + +public class CommentView extends AbstractView<Comment> implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * Author of the comment. + */ + private String author; + + /** + * Email of the comment. + */ + private String email; + + /** + * Content of the comment. + */ + private String content; + + /** + * Title of the comment. + */ + private String title; + + /** + * Is the comment visible on the map. + */ + private String pinned; + + /** + * Is the comment removed. + */ + private String removed; + + /** + * X coordinate on the map. + */ + private String xCoord; + + /** + * Y coordinate on the map. + */ + private String yCoord; + + /** + * Zoom level at which comment should be investigated on the map (to see + * details). + */ + private String zoom; + + private String submap; + + /** + * Constructor that initialize the view with the data from original comment. + * + * @param comment + * data required for initialization + */ + protected CommentView(final Comment comment) { + super(comment); + } + + /** + * Default constructor. Should be used only for deserialization. + */ + protected CommentView() { + } + + /** + * @return the author + * @see #author + */ + public String getAuthor() { + return author; + } + + /** + * @param author + * the author to set + * @see #author + */ + public void setAuthor(String author) { + this.author = author; + } + + /** + * @return the email + * @see #email + */ + public String getEmail() { + return email; + } + + /** + * @param email + * the email to set + * @see #email + */ + public void setEmail(String email) { + this.email = email; + } + + /** + * @return the content + * @see #content + */ + public String getContent() { + return content; + } + + /** + * @param content + * the content to set + * @see #content + */ + public void setContent(String content) { + this.content = content; + } + + /** + * @return the title + * @see #title + */ + public String getTitle() { + return title; + } + + /** + * @param title + * the title to set + * @see #title + */ + public void setTitle(String title) { + this.title = title; + } + + /** + * @return the pinned + * @see #pinned + */ + public String getPinned() { + return pinned; + } + + /** + * @param pinned + * the pinned to set + * @see #pinned + */ + public void setPinned(String pinned) { + this.pinned = pinned; + } + + /** + * @return the removed + * @see #removed + */ + public String getRemoved() { + return removed; + } + + /** + * @param removed + * the removed to set + * @see #removed + */ + public void setRemoved(String removed) { + this.removed = removed; + } + + /** + * @return the xCoord + * @see #xCoord + */ + public String getxCoord() { + return xCoord; + } + + /** + * @param xCoord + * the xCoord to set + * @see #xCoord + */ + public void setxCoord(String xCoord) { + this.xCoord = xCoord; + } + + /** + * @return the yCoord + * @see #yCoord + */ + public String getyCoord() { + return yCoord; + } + + /** + * @param yCoord + * the yCoord to set + * @see #yCoord + */ + public void setyCoord(String yCoord) { + this.yCoord = yCoord; + } + + /** + * @return the zoom + * @see #zoom + */ + public String getZoom() { + return zoom; + } + + /** + * @param zoom + * the zoom to set + * @see #zoom + */ + public void setZoom(String zoom) { + this.zoom = zoom; + } + + /** + * @param pinned + * the pinned to set + * @see #pinned + */ + public void setPinned(final boolean pinned) { + if (pinned) { + setPinned("YES"); + } else { + setPinned("NO"); + } + } + + /** + * Sets x coordinate. + * + * @param x + * x coordinate to set + * @see #xCoord + */ + public void setxCoord(double x) { + this.xCoord = x + ""; + } + + /** + * Sets y coordinate. + * + * @param y + * y coordinate to set + * @see #yCoord + */ + public void setyCoord(double y) { + this.yCoord = y + ""; + } + + /** + * @return the submap + * @see #submap + */ + public String getSubmap() { + return submap; + } + + /** + * @param submap the submap to set + * @see #submap + */ + public void setSubmap(String submap) { + this.submap = submap; + } +}; diff --git a/service/src/main/java/lcsb/mapviewer/services/view/CommentViewFactory.java b/service/src/main/java/lcsb/mapviewer/services/view/CommentViewFactory.java index f3cf4961cd..d5c1a44570 100644 --- a/service/src/main/java/lcsb/mapviewer/services/view/CommentViewFactory.java +++ b/service/src/main/java/lcsb/mapviewer/services/view/CommentViewFactory.java @@ -87,12 +87,14 @@ public class CommentViewFactory extends AbstractViewFactory<Comment, CommentView } } } - result.setTitle((title)); + result.setTitle(title); + if (comment.getSubmodelData() != null) { + result.setSubmap(comment.getSubmodelData().getId() + ""); + } if (coordinates != null) { result.setxCoord(coordinates.getX()); result.setyCoord(coordinates.getY()); result.setZoom("" + (Configuration.MIN_ZOOM_LEVEL + model.getZoomLevels() - 1)); - } return result; } diff --git a/web/src/main/webapp/WEB-INF/components/map/map.xhtml b/web/src/main/webapp/WEB-INF/components/map/map.xhtml index be6009b956..cc80c2722f 100644 --- a/web/src/main/webapp/WEB-INF/components/map/map.xhtml +++ b/web/src/main/webapp/WEB-INF/components/map/map.xhtml @@ -87,6 +87,12 @@ <p:remoteCommand name="_sendReferenceGenomeDetailRequest" actionListener="#{referenceGenomeMB.requestJavasciptGenomeDetails}" /> </h:form> + <h:form id="createSubmodelDialog"> + <p:remoteCommand name="_createSubmodelDialog" actionListener="#{mapMB.createSubmodelDialog}" async="false"/> + </h:form> + + + <!-- loading dialog used for informing user that data is being loaded --> <p:dialog header="Loading" widgetVar="loadingDlg" resizable="false" id="loadingDlg" showEffect="fade" modal="true" closable="false"> diff --git a/web/src/main/webapp/WEB-INF/components/map/submapPanel.xhtml b/web/src/main/webapp/WEB-INF/components/map/submapPanel.xhtml index 304a6d2987..c586e22bb2 100644 --- a/web/src/main/webapp/WEB-INF/components/map/submapPanel.xhtml +++ b/web/src/main/webapp/WEB-INF/components/map/submapPanel.xhtml @@ -19,21 +19,13 @@ <h:panelGroup layout="block" > <p:dataTable id="submapDataTable" var="submap" value="#{mapMB.mapDataList}"> -<!-- <p:column sortBy="id" headerText="Id"> - <h:outputText id="id" value="#{submap.mapConfig.idObject}" /> - </p:column> --> - <p:column sortBy="name" headerText="Name"> <h:outputText id="name" value="#{submap.mapConfig.name}" /> </p:column> -<!-- <p:column sortBy="type" headerText="Type"> - <h:outputText id="type" value="#{submap.type}" /> - </p:column> --> - <p:column headerText=""> <p:commandLink actionListener="#{mapMB.createSubmodelDialog}" - oncomplete="GuiConnector.openDialog(#{submap.mapConfig.idObject}); customMap.openLayoutById('#{mapMB.selectedLayoutIdentifier}');" id="opener" ajax="true" icon="ui-icon-document" title="View"> + oncomplete="GuiConnector.openDialog(#{submap.mapConfig.idObject});" id="opener" ajax="true" icon="ui-icon-document" title="View"> <f:param name="submodelId" value="#{submap.mapConfig.idObject}"/> <p:graphicImage height="24" width="24" diff --git a/web/src/main/webapp/admin/comments.xhtml b/web/src/main/webapp/admin/comments.xhtml index 40bb86deea..7da4892f98 100644 --- a/web/src/main/webapp/admin/comments.xhtml +++ b/web/src/main/webapp/admin/comments.xhtml @@ -29,7 +29,9 @@ </p:column> <p:column sortBy="title" headerText="Title"> - <h:link value="#{comment.title}" outcome="/index.xhtml?id=#{mapMB.currentMapId}&x=#{comment.xCoord}&y=#{comment.yCoord}&zoom=#{comment.zoom}&comments=on" target="_map"/> + <h:link value="#{comment.title}" + outcome="/index.xhtml?id=#{mapMB.currentMapId}&x=#{comment.xCoord}&y=#{comment.yCoord}&zoom=#{comment.zoom}&comments=on&submap=#{comment.submap}" + target="_map"/> </p:column> <p:column sortBy="author" headerText="Author"> diff --git a/web/src/main/webapp/index.xhtml b/web/src/main/webapp/index.xhtml index e1ce9d6856..f8b0016b34 100644 --- a/web/src/main/webapp/index.xhtml +++ b/web/src/main/webapp/index.xhtml @@ -84,12 +84,14 @@ var configuration = new Configuration(); function processUrlGetParams() { - if (GuiConnector.getParams["x"]!=undefined && GuiConnector.getParams["y"]!=undefined){ - ServerConnector.setCenterCoordinateX(GuiConnector.getParams["x"]); - ServerConnector.setCenterCoordinateY(GuiConnector.getParams["y"]); - } - if (GuiConnector.getParams["zoom"]!=undefined ){ - ServerConnector.setZoomLevel(GuiConnector.getParams["zoom"]); + if (GuiConnector.getParams["submap"]==null) { + if (GuiConnector.getParams["x"]!=undefined && GuiConnector.getParams["y"]!=undefined){ + ServerConnector.setCenterCoordinateX(GuiConnector.getParams["x"]); + ServerConnector.setCenterCoordinateY(GuiConnector.getParams["y"]); + } + if (GuiConnector.getParams["zoom"]!=undefined){ + ServerConnector.setZoomLevel(GuiConnector.getParams["zoom"]); + } } } @@ -156,6 +158,26 @@ function initMap(){ //when I try to hide legend from the beginning or in the same thread it's hidden forever... ;/ setTimeout(function() { GuiConnector.hideLegend(); + var submodelId = GuiConnector.getParams["submap"]; + if (submodelId!=undefined) { + _createSubmodelDialog([{name:'submodelId', value: submodelId}]); + //for some reason the call above is not sync (even though it's required) + var waitingForResponse = setInterval(function() { + if (GuiConnector.getJsPopupForSubmodelId(submodelId)!=null) { + GuiConnector.openDialog(submodelId); + clearInterval(waitingForResponse); + if (GuiConnector.getParams["zoom"]!=undefined){ + customMap.setZoom(submodelId,parseInt(GuiConnector.getParams["zoom"])); + } + if (GuiConnector.getParams["x"]!=undefined && GuiConnector.getParams["y"]!=undefined){ + var x = GuiConnector.getParams["x"]; + var y = GuiConnector.getParams["y"]; + var point = new google.maps.Point(x, y); + customMap.setCenter(submodelId,point); + } + } + },100); + } }, 0); } @@ -218,16 +240,6 @@ function removeComment(id) { <p:tab id="infoTab" title="<div class='tngContainer'><div class='tng'></div></div><div class='maintabdiv'><i class='fa fa-info maintab'></i><br>PROJECT</div>" styleClass="leftTab"> <ui:include src="/WEB-INF/components/map/infoPanel.xhtml" /> </p:tab > -<!-- -<p:tab id="sample1" title="<div class='tngContainer'><div class='tng'></div></div><div class='maintabdiv'><i class='fa fa-envelope maintab'></i><br>SAMPLE 1</div>" styleClass="leftTab hide"> -</p:tab > - -<p:tab id="sample2" title="<div class='tngContainer'><div class='tng'></div></div><div class='maintabdiv'><i class='fa fa-envelope maintab'></i><br>SAMPLE 2</div>" styleClass="leftTab hide"> -</p:tab > - -<p:tab id="sample3" title="<div class='tngContainer'><div class='tng'></div></div><div class='maintabdiv'><i class='fa fa-envelope maintab'></i><br>SAMPLE 3</div>" styleClass="leftTab hide"> -</p:tab > ---> </p:tabView > diff --git a/web/src/main/webapp/resources/js/CustomMap.js b/web/src/main/webapp/resources/js/CustomMap.js index 443eb5ab98..5cc4d04870 100644 --- a/web/src/main/webapp/resources/js/CustomMap.js +++ b/web/src/main/webapp/resources/js/CustomMap.js @@ -1,1735 +1,1741 @@ -/** - * Default constructor. - * - * @param globalMap - * google.maps.Map object representing the map - * @param configuration - * Configuration object representing our data in the map - * @param bigButtons - * boolean value determining if the buttons on the map should be big, - * and if the map is run on the touch interface - * @param hideDiv - * - */ -function CustomMap(options) { - if (!(options instanceof CustomMapOptions)) { - options = new CustomMapOptions(options); - } - AbstractCustomMap.call(this, options); - - // set config parameters - this.map = options.getMap(); - - if (options.isCustomTouchInterface()) { - this._touchInterface = new TouchMap(this); - } - - // create function that override primefaces fitBounds with default google - // implementation - var fitBounds = function(bounds) { - var tmp = this.fitBounds; - this.fitBounds = google.maps.Map.prototype.fitBounds; - this.fitBounds(bounds); - this.fitBounds = tmp; - }; - this.map.fitBounds2 = fitBounds; - - this.buttons = []; - - this.createSubmaps(); - - this.selectedLayouts = []; - - this.setupLayouts(); - - this.createBelt(); - - this.customizeGoogleMapView(); - - this.createMapChangedCallbacks(); - - this.createClientServerListeners(); - - this.overlayCollections = []; - - // which submap is active (where user made interaction for the last time) - this._activeSubmapId = null; - - this.initialized = true; - - // list of reference genomes - this._referenceGenome = []; - - ServerConnector.actualizeSessionData(); -} - -CustomMap.prototype = Object.create(AbstractCustomMap.prototype); - -CustomMap.prototype.constructor = CustomMap; - -CustomMap.prototype.createSubmaps = function() { - this.submaps = []; - for (var i = 0; i < this.getConfiguration().SUBMODELS.length; i++) { - this.submaps.push(new Submap(this, - this.getConfiguration().SUBMODELS[i].ID_MODEL)); - } -}; - -CustomMap.prototype.createLogo = function() { - - var logoControlDiv = document.createElement('DIV'); - var logo = document.createElement('IMG'); - var url = ServerConnector.getLogoImg(); - if (!/^(f|ht)tps?:\/\//i.test(url)) { - url = GuiConnector.getImgPrefix() + url; - } - logo.src = url; - logo.style.cursor = 'pointer'; - logo.style.width = "80px"; - logoControlDiv.appendChild(logo); - google.maps.event.addDomListener(logo, 'click', function() { - var win = window.open(ServerConnector.getLogoLink(), '_blank'); - win.focus(); - }); - logoControlDiv.index = 0; // used for ordering - this.map.controls[google.maps.ControlPosition.LEFT_BOTTOM] - .push(logoControlDiv); - - var logoControlDiv = document.createElement('DIV'); - logoControlDiv.style.padding = '5px'; - - var logo = document.createElement('IMG'); - logo.src = GuiConnector.getImgPrefix() - + GuiConnector.getLcsbLogoImg(this.bigButtons); - logo.style.cursor = 'pointer'; - logoControlDiv.appendChild(logo); - google.maps.event.addDomListener(logo, 'click', function() { - var win = window.open('http://wwwen.uni.lu/lcsb/', '_blank'); - win.focus(); - }); - - logoControlDiv.index = 1; // used for ordering - this.map.controls[google.maps.ControlPosition.RIGHT_BOTTOM] - .push(logoControlDiv); -}; - -CustomMap.prototype.createBelt = function() { - var self = this; - - this.divBelt = document.createElement('DIV'); - this.divBelt.className = "headerBelt"; - - var hideDivButton = document.createElement('DIV'); - hideDivButton.className = "headerHideDivButton"; - - var hideButton = document.createElement('button'); - hideButton.id = "hide_button"; - hideButton.className = "headerHideButton"; - hideButton.innerHTML = "<i class='fa fa-chevron-left'></i>"; - // when there is no div to hide we should allow hiding - if (self.getHideDiv() !== undefined) { - hideButton.onclick = (function() { - var button = hideButton; - var div = self.getHideDiv(); - - var left = $(PrimeFaces.escapeClientId(self.map.getDiv().id)).offset().left; - return function() { - if (button.innerHTML.indexOf('fa-chevron-left') > 0) { - button.innerHTML = "<i class='fa fa-chevron-right'></i>"; - div.style.display = 'none'; - self.map.getDiv().style.left = "0px"; - } else { - div.style.display = 'block'; - button.innerHTML = "<i class='fa fa-chevron-left'></i>"; - self.map.getDiv().style.left = left + "px"; - } - google.maps.event.trigger(self.map, 'resize'); - return false; - }; - })(); - } else { - hideButton.disabled = true; - logger.warn("Left panel hiding disabled"); - } - hideDivButton.appendChild(hideButton); - hideDivButton.index = 1; // used for ordering - this.divBelt.appendChild(hideDivButton); - - var controlText = document.createElement('div'); - controlText.className = "headerTextBold"; - controlText.innerHTML = this.getConfiguration().MAP_NAME; - this.divBelt.appendChild(controlText); - - this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(this.divBelt); -}; - -CustomMap.prototype.setLegendVisible = function(vis) { - if (vis) { - document.getElementById('legend').style.display = 'block'; - } else { - document.getElementById('legend').style.display = 'none'; - } -}; - -CustomMap.prototype.clearOverlays = function() { - for ( var overlayName in this.overlayCollections) { - if (this.overlayCollections.hasOwnProperty(overlayName)) { - var collection = this.overlayCollections[overlayName]; - this.clearOverlayCollection(collection); - } - } -}; - -CustomMap.prototype.refreshOverlays = function() { - for ( var overlayName in this.overlayCollections) { - if (this.overlayCollections.hasOwnProperty(overlayName)) { - var collection = this.overlayCollections[overlayName]; - collection.refresh(); - } - } -}; - -/** - * Removes all markers from {@link OverlayCollection}. - * - * @param collection - * {@link OverlayCollection} from which all markers should be removed - */ -CustomMap.prototype.clearOverlayCollection = function(collection) { - logger.debug("Clear collection: " + collection.name); - for ( var key in collection.aliasMarkers) { - if (collection.aliasMarkers.hasOwnProperty(key) - && collection.aliasMarkers[key] != null) { - collection.aliasMarkers[key].setMap(null); - } - } - - for ( var key in collection.pointMarkers) { - if (collection.pointMarkers.hasOwnProperty(key) - && collection.pointMarkers[key] != null) { - - collection.pointMarkers[key].setMap(null); - } - } - - for ( var key in collection.reactionMarkers) { - if (collection.reactionMarkers.hasOwnProperty(key) - && collection.reactionMarkers[key] != null) { - collection.reactionMarkers[key].setMap(null); - } - } - - collection.aliasMarkers = []; - collection.pointMarkers = []; - collection.reactionMarkers = []; -}; - -/** - * Updates data about visualized markers in {@link OverlayCollection}. - * - * @param overlayCollection - * {@link OverlayCollection} with new data to visualize - * @param fitBounds - * <code>true</code> id the map should fit bounds to the new - * elements after update, <code>false</code> otherwise - */ -CustomMap.prototype.updateOverlayCollection = function(overlayCollection, - fitBounds) { - this.clearOverlayCollection(overlayCollection); - this.renderOverlayCollection(overlayCollection, fitBounds); -}; - -/** - * This method open layout by a given layout identifier (string starting with - * 'cv' prefix) in a map and all submaps. - * - * @param identifier - * identifier of the layout to present - */ -CustomMap.prototype.openLayout = function(identifier) { - logger.debug("Opening layout: " + identifier); - - this.map.setMapTypeId(identifier); - - var index = null; - for (var i = 0; i < this.getConfiguration().MAPS.length; i++) { - if ('cv' + this.getConfiguration().MAPS[i].idObject == identifier) { - index = i; - } - } - if (index == null) { - logger.warn("Invalid layout identifier: " + identifier); - } - for (var i = 0; i < this.submaps.length; i++) { - this.submaps[i].openLayout('cv' - + this.submaps[i].getConfiguration().MAPS[index].idObject); - } -}; - -/** - * This method open layout by a given database identifier. - * - * @param identifier - * identifier of the layout to present - */ -CustomMap.prototype.openLayoutById = function(identifier) { - logger.debug("Opening layout: " + identifier); - var index = null; - for (var i = 0; i < configuration.MAPS.length; i++) { - if (configuration.MAPS[i].idObject == identifier) { - index = 'cv' + identifier; - } - } - - // if layout doesn't exist print error - if (index == null) { - alert("You have no privileges for selected layout"); - } else { - this.openLayout(index); - } -}; - -CustomMap.prototype.createMapMenu = function(layoutButtons) { - var selfMap = this; - - var buttons = []; - - // create a button for overview images when the image is available - if (this.getConfiguration().TOP_OVERVIEW_IMAGE != "undefined" - && this.getConfiguration().TOP_OVERVIEW_IMAGE != null) { - var submenuButtonDiv = document.createElement('button'); - buttons.push(submenuButtonDiv); - submenuButtonDiv.id = "overview_button"; - submenuButtonDiv.innerHTML = "<i class='fa fa-sitemap' style='font-size:18px; font-weight:400; padding-right:10px;'></i> SHOW OVERVIEW"; - submenuButtonDiv.className = "overview_button"; - submenuButtonDiv.onclick = (function() { - return function() { - selfMap.showOverview(); - return false; - }; - })(); - this.divBelt.appendChild(submenuButtonDiv); - } - - var rightHeaderMenu = document.createElement('div'); - rightHeaderMenu.className = "rightHeaderMenu"; - var submenuDiv = document.createElement('div'); - submenuDiv.className = "div4checkboxes"; - var submenuButtonDiv = document.createElement('input'); - submenuButtonDiv.type = "checkbox"; - submenuButtonDiv.name = "Comments"; - submenuButtonDiv.id = "comment_checkbox"; - submenuButtonDiv.onclick = (function() { - var selfButton = submenuButtonDiv; - return function() { - selfMap.showComments = selfButton.checked; - ServerConnector.setShowComments(selfButton.checked); - if (selfButton.checked) { - document.getElementById('refresh_comments_button').style.display = 'inline'; - } else { - document.getElementById('refresh_comments_button').style.display = 'none'; - } - selfMap.refreshComments(); - - }; - })(); - var element = document.createElement('label'); - element.innerHTML = "COMMENTS"; - element.setAttribute("for", "comment_checkbox"); - submenuDiv.appendChild(submenuButtonDiv); - submenuDiv.appendChild(element); - - var submenuButtonDiv = document.createElement('input'); - submenuButtonDiv.type = "checkbox"; - submenuButtonDiv.name = "Legend"; - submenuButtonDiv.id = "lengend_checkbox"; - submenuButtonDiv.onclick = (function() { - var selfButton = submenuButtonDiv; - return function() { - if (selfButton.checked) { - GuiConnector.showLegend(); - } else { - GuiConnector.hideLegend(); - } - }; - })(); - element = document.createElement('label'); - element.innerHTML = "LEGEND"; - element.setAttribute("for", "lengend_checkbox"); - submenuDiv.appendChild(submenuButtonDiv); - submenuDiv.appendChild(element); - - submenuButtonDiv = document.createElement('button'); - submenuButtonDiv.id = "refresh_comments_button"; - submenuButtonDiv.innerHTML = "<i class='fa fa-refresh' style='font-size:21px; font-weight:400;'></i>"; - submenuButtonDiv.className = "overview_button"; - submenuButtonDiv.style.display = 'none'; - submenuButtonDiv.onclick = (function() { - return function() { - selfMap.refreshComments(); - return false; - }; - })(); - submenuDiv.appendChild(submenuButtonDiv); - rightHeaderMenu.appendChild(submenuDiv); - - var submenuButtonDiv = document.createElement('button'); - buttons.push(submenuButtonDiv); - submenuButtonDiv.id = "clear_button"; - submenuButtonDiv.className = "overview_button"; - submenuButtonDiv.innerHTML = "<i class='fa fa-times' style='font-size:18px; font-weight:300; padding-right:10px;'></i> CLEAR"; - submenuButtonDiv.title = "Clear all queries"; - submenuButtonDiv.style.display = 'inline'; - submenuButtonDiv.onclick = (function() { - return function() { - selfMap.clearData(); - return false; - }; - })(); - rightHeaderMenu.appendChild(submenuButtonDiv); - - this.divBelt.appendChild(rightHeaderMenu); -}; - -CustomMap.prototype.registerSource = function(overlayCollection) { - this.overlayCollections[overlayCollection.name] = overlayCollection; - overlayCollection.aliasMarkers = []; - overlayCollection.pointMarkers = []; - overlayCollection.reactionMarkers = []; -}; - -CustomMap.prototype.refreshComments = function() { - for ( var overlayName in this.overlayCollections) { - if (this.overlayCollections.hasOwnProperty(overlayName) - && overlayName == "comment") { - var collection = this.overlayCollections[overlayName]; - collection.refresh(); - return; - } - } - throw "comment OverlayCollection not found"; -}; - -CustomMap.prototype.turnOnOffDrawing = function() { - var model = this.getSubmodelById(this.getActiveSubmapId()); - if (model != null) { - model._turnOnOffDrawing(); - } else { - throw "Cannot find submodel with id: " + this.getActiveSubmapId(); - } -}; - -CustomMap.prototype.clearData = function() { - this.clearOverlays(); - for ( var overlayName in this.overlayCollections) { - if (this.overlayCollections.hasOwnProperty(overlayName)) { - ServerConnector.sendClearRequest(overlayName); - } - } -}; - -CustomMap.prototype.refreshMarkers = function() { - logger.debug("Refresh Markers: "); - for ( var overlayName in this.overlayCollections) { - if (this.overlayCollections.hasOwnProperty(overlayName)) { - var collection = this.overlayCollections[overlayName]; - this.refreshOverlayMarkers(collection); - } - } -}; - -CustomMap.prototype.refreshOverlayMarkers = function(overlay) { - var self = this; - logger.debug("Refresh overlay: " + overlay.name); - var boundsArray = []; - boundsArray[this.getId()] = new google.maps.LatLngBounds(); - for (var i = 0; i < this.submaps.length; i++) { - boundsArray[this.submaps[i].getId()] = new google.maps.LatLngBounds(); - } - - var updated = false; - var stillMissing = false; - for ( var key in overlay.aliasMarkers) { - if (overlay.aliasMarkers.hasOwnProperty(key) - && overlay.aliasMarkers[key] != null) { - var alias = overlay.aliasMarkers[key]; - if (alias.getAliasData() == null) { - var aliasData = alias.getCustomMap().mapModel.getAliasById(alias - .getId()); - if (aliasData != null) { - alias.setAliasData(aliasData); - alias.init(); - alias.show(); - updated = true; - var bounds = alias.getBounds(); - boundsArray[alias.getCustomMap().getId()].extend(bounds - .getNorthEast()); - } else { - stillMissing = true; - logger.debug("Cannot show alias marker. Data is still not loaded..."); - } - } else { - var bounds = alias.getBounds(); - if (!this.isMarkerOptimization()) { - alias.hide(); - alias.show(); - } - boundsArray[alias.getCustomMap().getId()].extend(bounds.getNorthEast()); - boundsArray[alias.getCustomMap().getId()].extend(bounds.getSouthWest()); - } - } - } - - for ( var key in overlay.pointMarkers) { - if (overlay.pointMarkers.hasOwnProperty(key) - && overlay.pointMarkers[key] != null) { - var alias = overlay.pointMarkers[key]; - // we don't need to update this markers because thet data about - // visualization is - // already there - // alias.update(); - var bounds = alias.getBounds(); - if (!this.isMarkerOptimization()) { - alias.hide(); - alias.show(); - } - boundsArray[alias.getCustomMap().getId()].extend(bounds.getNorthEast()); - } - } - - for ( var key in overlay.reactionMarkers) { - if (overlay.reactionMarkers.hasOwnProperty(key) - && overlay.reactionMarkers[key] != null) { - var reactionOverlay = overlay.reactionMarkers[key]; - if (reactionOverlay.getReactionData() == null) { - var reactionData = reactionOverlay.getCustomMap().mapModel - .getReactionById(reactionOverlay.getId()); - if (reactionData != null) { - reactionOverlay.setReactionData(reactionData); - reactionOverlay.init(); - reactionOverlay.show(); - updated = true; - var bounds = reactionOverlay.getBounds(); - boundsArray[reactionOverlay.getCustomMap().getId()].extend(bounds - .getNorthEast()); - boundsArray[reactionOverlay.getCustomMap().getId()].extend(bounds - .getSouthWest()); - } else { - stillMissing = true; - logger - .debug("Cannot show reaction marker. Data is still not loaded..."); - } - } else { - var bounds = alias.getBounds(); - if (!this.isMarkerOptimization()) { - alias.hide(); - alias.show(); - } - boundsArray[alias.getCustomMap().getId()].extend(bounds.getNorthEast()); - boundsArray[alias.getCustomMap().getId()].extend(bounds.getSouthWest()); - } - - } - } - - if (!stillMissing && updated && overlay.fitBounds) { - for ( var mapId in boundsArray) { - if (boundsArray.hasOwnProperty(mapId)) { - var map = this.getSubmodelById(mapId).map; - var bounds = boundsArray[mapId]; - if (map != null && !bounds.isEmpty()) { - if (typeof map.fitBounds2 !== "undefined") { - map.fitBounds2(bounds); - } else { - map.fitBounds(bounds); - } - } - } - } - } -}; - -CustomMap.prototype.openSubmodel = function(id, htmlTag, jsVar) { - if (jsVar.submapControler == null) { - var submap = null; - for (var i = 0; i < this.submaps.length; i++) { - if (this.submaps[i].getId() == id) { - submap = this.submaps[i]; - } - } - if (submap == null) { - logger.error("Unknown submap for id: " + id); - } else { - submap.init(htmlTag, jsVar); - submap.openLayout(this.map.getMapTypeId()); - this.refreshOverlays(); - - // now we have to visualize layouts - var layouts = []; - - // get list of layouts - for ( var key in this.selectedLayouts) { - if (this.selectedLayouts.hasOwnProperty(key) - && this.selectedLayouts[key] == true) { - layouts.push(key); - } - } - - // show layouts that should be visualized (resize or show them) - for (var i = 0; i < layouts.length; i++) { - var layoutId = layouts[i]; - submap._showSelectedLayout(layoutId, i, layouts.length); - } - } - } - jsVar.show(); -}; - -CustomMap.prototype.customizeGoogleMapView = function() { - var mapOptions = this.creatMapOptions(); - this.map.setOptions(mapOptions); - - this.createMapMenu(false); - - this.registerMapClickEvents(); - - this.createLogo(); - // this.createMapVersion(); - google.maps.event.trigger(this.map, 'resize'); - google.maps.event.trigger(this.map, 'maptypeid_changed'); - google.maps.event.trigger(this.map, 'projection_changed'); - - // center map and zoom in to fit into browser window - if (this.getConfiguration().fitMapBounds) { - var bounds = new google.maps.LatLngBounds(); - var point = new google.maps.LatLng( - this.getConfiguration().topLeftLatLng.lat, - this.getConfiguration().topLeftLatLng.lng); - bounds.extend(point); - - point = new google.maps.LatLng( - this.getConfiguration().bottomRightLatLng.lat, - this.getConfiguration().bottomRightLatLng.lng); - bounds.extend(point); - - if (typeof this.map.fitBounds2 !== "undefined") { - this.map.fitBounds2(bounds); - } else { - this.map.fitBounds(bounds); - } - } -}; - -CustomMap.prototype.setCenter = function(mapIdentifier, coordinates) { - if (this.getConfiguration().ID_MODEL == mapIdentifier) { - this.map.setCenter(coordinates); - } else { - openDialog(mapIdentifier); - for (var i = 0; i < this.submaps.length; i++) { - if (this.submaps[i].getId() == mapIdentifier) { - this.submaps[i].map.setCenter(coordinates); - } - } - } -}; - -CustomMap.prototype.setZoom = function(mapIdentifier, zoom) { - if (this.getConfiguration().ID_MODEL == mapIdentifier) { - this.map.setZoom(zoom); - } else { - openDialog(mapIdentifier); - for (var i = 0; i < this.submaps.length; i++) { - if (this.submaps[i].getId() == mapIdentifier) { - this.submaps[i].map.setZoom(zoom); - } - } - } -}; - -/** - * Creates listeners for google.maps.Map object that will actualize the data in - * user session. - */ -CustomMap.prototype.createMapChangedCallbacks = function() { - var customMapSelf = this; - // listener for changing zoom level - google.maps.event.addListener(this.map, 'zoom_changed', function() { - ServerConnector.setZoomLevel(customMapSelf.map.getZoom()); - ServerConnector.actualizeSessionData(); - }); - - // if we have zoom level data stored in session then restore it - var level = ServerConnector.getZoomLevel(); - if (parseInt(level) > 0) { - level = parseInt(level); - this.map.setZoom(level); - } else { - ServerConnector.setZoomLevel(customMapSelf.map.getZoom()); - } - - // listener for changing location of the map (moving left/reght/top/bottom - google.maps.event.addListener(this.map, 'center_changed', function() { - var coord = customMapSelf.map.getCenter(); - var point = customMapSelf.fromLatLngToPoint(coord); - ServerConnector.setCenterCoordinateX(point.x); - ServerConnector.setCenterCoordinateY(point.y); - ServerConnector.actualizeSessionData(); - }); - - // if we have coordinate data stored in session then restore it - var x = ServerConnector.getCenterCoordinateX(); - var y = ServerConnector.getCenterCoordinateY(); - if (!isNaN(x) && !isNaN(y)) { - var point = new google.maps.Point(x, y); - var coord = customMapSelf.fromPointToLatLng(point); - customMapSelf.map.setCenter(coord); - } - - // listener for changing type of layout - google.maps.event.addListener(this.map, 'maptypeid_changed', function() { - ServerConnector.setSelectedLayout(customMapSelf.map.getMapTypeId()); - ServerConnector.actualizeParams(); - }); - - // if we have type of layout stored in the session then restore it - var mapType = ServerConnector.getSelectedLayout(); - if (mapType != "" && mapType != null) { - this.openLayout(mapType); - } -}; - -/** - * Returns submodel (or this model) by identfier of the model. - * - * @param identifier - * identifier of the submodel - * @returns submodel (or this model) with given identfier of the model - */ -CustomMap.prototype.getSubmodelById = function(identifier) { - if (this.getId() == identifier) { - return this; - } - for (var i = 0; i < this.submaps.length; i++) { - if (this.submaps[i].getId() == identifier) { - return this.submaps[i]; - } - } - return null; -}; - -CustomMap.prototype.removeSelection = function() { - var model = this.getSubmodelById(this.getActiveSubmapId()); - if (model != null) { - model._removeSelection(); - } else { - throw "Cannot find submodel with id: " + this.getActiveSubmapId(); - } -}; - -/** - * This method will hide google map view and will present single image overview - * of the data. - */ -CustomMap.prototype.showOverview = function(overviewImageId) { - overviewDialog.syncWindowResize(); - if (this.getOverviewDiv() == "undefined" || this.getOverviewDiv() == null) { - logger.warn("Cannot show overview, because overview div is undefined"); - } else { - logger.debug("Show overview"); - overviewDialog.show(); - - // resize dialog - var htmlTag = GuiConnector.getOverviewHtmlTag(); - - var width = Math.floor(window.innerWidth * 2 / 3); - var height = Math.floor(window.innerHeight * 2 / 3); - - htmlTag.style.height = (height + 50) + "px"; - htmlTag.style.width = (width + 20) + "px"; - - var self = this; - - // remove all child nodes from overview div - while (this.getOverviewDiv().hasChildNodes()) { - this.getOverviewDiv().removeChild(this.getOverviewDiv().lastChild); - } - - if (overviewImageId == "undefined" || overviewImageId == null) { - this.overviewImage = this.getConfiguration().TOP_OVERVIEW_IMAGE; - } else { - this.overviewImage = null; - for (var i = 0; i < this.getConfiguration().OVERVIEW_IMAGES.length; i++) { - if (this.getConfiguration().OVERVIEW_IMAGES[i].idObject == overviewImageId) { - this.overviewImage = this.getConfiguration().OVERVIEW_IMAGES[i]; - } - } - - if (this.overviewImage == null) { - logger.warn("Unknown overview image with id = " + overviewImageId); - this.overviewImage = this.getConfiguration().TOP_OVERVIEW_IMAGE; - } - } - - // add image to overview div - this.overviewImageTag = document.createElement("IMG"); - this.overviewImageTag.src = "../map_images/" + this.overviewImage.filename; - this.getOverviewDiv().appendChild(this.overviewImageTag); - - var ratio = 1.0; - - // check how image should be resized to fit dialog and resize it manually!!! - if (width / this.overviewImage.width > height / this.overviewImage.height) { - this.overviewImageTag.style.height = height + "px"; - ratio = height / this.overviewImage.height; - width = this.overviewImage.width * ratio; - - htmlTag.style.width = (width + 20) + "px"; - } else { - this.overviewImageTag.style.width = width + "px"; - ratio = width / this.overviewImage.width; - height = this.overviewImage.height * ratio; - - htmlTag.style.height = (height + 50) + "px"; - } - - // center dialog - overviewDialog.jq.css("top", Math.max(0, - (($(window).height() - overviewDialog.jq.outerHeight()) / 2) - + $(window).scrollTop()) - + "px"); - overviewDialog.jq.css("left", Math.max(0, - (($(window).width() - overviewDialog.jq.outerWidth()) / 2) - + $(window).scrollLeft()) - + "px"); - - // on click event (what should happen when we click on the image) - var onclickevent = function getClickPosition(e) { - var parentPosition = getPosition(e.currentTarget); - var xPosition = e.clientX - parentPosition.x; - var yPosition = e.clientY - parentPosition.y; - - var imgWidth = self.overviewImageTag.offsetWidth; - - var currentRatio = imgWidth / self.overviewImage.width; - - var xNormal = xPosition / currentRatio; - var yNormal = yPosition / currentRatio; - var point = { - x : xNormal, - y : yNormal - }; - - var link = null; - for (var i = 0; i < self.overviewImage.links.length; i++) { - if (pointInsidePolygon(point, self.overviewImage.links[i].polygon)) { - if (link == null) { - link = self.overviewImage.links[i]; - } else { - logger.warn("More than one link found. Skipping"); - } - } - } - if (link != null) { - if (link.type == "OverviewModelLink") { - logger.debug("Opening model from overview. ModelId: " - + link.modelLinkId); - logger.debug("link coordinates [" + link.idObject + "]: " - + link.latLng); - // TODO min zoom value can be different for every map, it should be - // changed in the future - self.showModel(link.modelLinkId, link.latLng, link.zoomLevel - + self.getConfiguration().MIN_ZOOM); - overviewDialog.hide(); - } else if (link.type == "OverviewImageLink") { - logger.debug("Opening image from overview. ImageId: " - + link.imageLinkId); - self.showOverview(link.imageLinkId); - } else if (link.type == "OverviewSearchLink") { - logger.debug("Sending search query. Query: " + link.query); - searchPanel.search(link.query); - overviewDialog.hide(); - } else { - logger.warn("Unknown type of link: " + link.type - + ". Don't know what to do... LinkId: " + link.idObject); - } - } - }; - - this.overviewImageTag.onclick = onclickevent; - - // resize canvas where on mouse over highligh will appear - var canvas = document.getElementById("canvasDebug"); - canvas.width = width; - canvas.height = height; - canvas.onclick = onclickevent; - - // in debug mode draw clickable shapes - if (DEBUG_ON) { - var ctx = canvas.getContext("2d"); - // clear canvas - ctx.clearRect(0, 0, canvas.width, canvas.height); - for (var i = 0; i < this.overviewImage.links.length; i++) { - ctx.beginPath(); - var polygon = this.overviewImage.links[i].polygon; - for (var j = 0; j < polygon.length; j++) { - var x = polygon[j].x * ratio; - var y = polygon[j].y * ratio; - ctx.moveTo(x, y); - x = polygon[(j + 1) % polygon.length].x * ratio; - y = polygon[(j + 1) % polygon.length].y * ratio; - ctx.lineTo(x, y); - } - ctx.stroke(); - } - } - - this.overviewImage.mousePos = { - x : 0, - y : 0 - }; - - // this listener should be called when mouse moves over image, it purpose is - // to change coursor to pointer when mouse enters clickable polygon and back - // to normal when mouse leaves such region - var onmousemove = function getMouseOverPosition(e) { - var position = getPosition(e.currentTarget); - position.x = e.clientX - position.x; - position.y = e.clientY - position.y; - - var imgWidth = self.overviewImageTag.offsetWidth; - - var currentRatio = imgWidth / self.overviewImage.width; - - var xNormal = position.x / currentRatio; - var yNormal = position.y / currentRatio; - var point = { - x : xNormal, - y : yNormal - }; - - if (self.overviewImage.mousePos.x != position.x - || self.overviewImage.mousePos.y != position.y) { - self.overviewImage.mousePos = position; - var link = null; - for (var i = 0; i < self.overviewImage.links.length; i++) { - if (pointInsidePolygon(point, self.overviewImage.links[i].polygon)) { - link = self.overviewImage.links[i]; - } - } - if (link == null) { - e.currentTarget.style.cursor = "auto"; - } else { - e.currentTarget.style.cursor = "pointer"; - } - } - }; - - // onmousemove listener should be assigned to canvas (which is on top of the - // image) and overviewimage (just in case something went wrong with resizing - // canvas) - canvas.onmousemove = onmousemove; - this.overviewImageTag.onmousemove = onmousemove; - } -}; - -CustomMap.prototype.showModel = function(id, point, zoomLevel) { - if (point != "undefined") { - this.setCenter(id, point); - } else { - logger.warn("Center point undefined..."); - } - if (zoomLevel != "undefined") { - this.setZoom(id, zoomLevel); - } else { - logger.warn("Zoom level undefined..."); - } -}; - -/** - * Adds information about aliases visible in the specific layout. - * - * @param layoutId - * identifier of the layout - * - * @param jsonAliases - * list of aliases in json format - * - */ -CustomMap.prototype.addAliasesForLayout = function(layoutId, jsonAliases) { - logger.debug("Adding aliases for layout: " + layoutId); - - // init layout data - if (this.mapModel.getLayoutDataById(layoutId) == null) { - this.mapModel.initLayoutData(layoutId); - for (var i = 0; i < this.submaps.length; i++) { - this.submaps[i].mapModel.initLayoutData(layoutId); - } - } - - var aliases = JSON.parse(jsonAliases); - for (var i = 0; i < aliases.length; i++) { - var alias = aliases[i]; - var model = this.getSubmodelById(alias.modelId); - if (model != 'undefined' && model != null) { - model.mapModel.addAliasForLayout(layoutId, alias); - } else { - logger.warn("Unknown model: " + alias.modelId); - } - } - - this.retrieveMissingAliases(); -} - -/** - * Adds information about aliases. - * - * @param jsonAliases - * list of aliases in json format - * - */ -CustomMap.prototype.addAliases = function(aliases) { - for (var i = 0; i < aliases.length; i++) { - var alias = aliases[i]; - var model = this.getSubmodelById(alias.modelId); - if (model != 'undefined' && model != null) { - model.addAlias(alias); - } else { - logger.warn("Unknown model: " + alias.modelId); - } - } - this.callListeners("onAddAliases"); -} - -/** - * This function will ask server for aliases that should be visualized but the - * data is still missing on the client side. - */ -CustomMap.prototype.retrieveMissingAliases = function() { - var ids = []; - var missing = this.mapModel.getMissingAliasIds(); - for (var j = 0; j < missing.length; j++) { - ids.push([ this.getId(), missing[j] ]); - } - for (var i = 0; i < this.submaps.length; i++) { - missing = this.submaps[i].mapModel.getMissingAliasIds(); - for (var j = 0; j < missing.length; j++) { - ids.push([ this.submaps[i].getId(), missing[j] ]); - } - } - if (ids.length > 0) { - // load data from server about missing aliases - ServerConnector.retreiveLightAliases(ids); - } - if (!ServerConnector.isWaitingForData()) { - // if we already have everything then just refresh data to be visualized - this.refreshSelectedLayouts(); - //and close "loading" dialog - GuiConnector.closeLoadingDialog(); - } -} - -/** - * Adds layout to be visualized. - * - * @param identifier - * identifier of the layout that should be included in visualization - */ -CustomMap.prototype.addSelectedLayout = function(identifier, name) { - logger.debug("Selecting layout: " + identifier); - - if (this.selectedLayouts[identifier] == true) { - logger.warn("Layout " + identifier + " already selected"); - } else { - this.selectedLayouts[identifier] = true; - - // open dialog with info that we are loading data (it takes some time for - // bigger layouts on big maps) - GuiConnector.openLoadingDialog(); - - // if we don't have information about this layout then download it - if (this.mapModel.getLayoutDataById(identifier) == null) { - // initialize what we can on client side - this.mapModel.initLayoutData(identifier, name); - for (var i = 0; i < this.submaps.length; i++) { - this.submaps[i].mapModel.initLayoutData(identifier, name); - } - - // load data from server about this layout - ServerConnector.retreiveActiveAliasesForLayout(identifier); - - // load data from server about this layout - ServerConnector.retreiveActiveReactionsForLayout(identifier); - } - if (!ServerConnector.isWaitingForData()) { - // if we already loaded the data then just visualize it - this.refreshSelectedLayouts(); - //and close "loading" dialog (if opened) - GuiConnector.closeLoadingDialog(); - } - // if we have to load data from server then open info window should be - // opened - ServerConnector - .setVisibleLayouts(JSON.stringify(this.getSelectedLayouts())); - - } -}; - -/** - * Returns list of layouts that are selected and visualized by javascript. - * - * @return array with a list of selected layotus - * - */ -CustomMap.prototype.getSelectedLayouts = function() { - var layouts = []; - - // get list of layouts - for ( var key in this.selectedLayouts) { - if (this.selectedLayouts.hasOwnProperty(key) - && this.selectedLayouts[key] == true) { - layouts.push(key); - } - } - return layouts; -} - -/** - * Removes layout from visualization. - * - * @param identifier - * identifier of layout to remove - * - */ -CustomMap.prototype.removeSelectedLayout = function(identifier) { - logger.debug("Removing layout: " + identifier); - - if (this.selectedLayouts[identifier] != true) { - logger.warn("Layout " + identifier + " is not selected"); - } else { - this.selectedLayouts[identifier] = false; - this.refreshSelectedLayouts(); - ServerConnector - .setVisibleLayouts(JSON.stringify(this.getSelectedLayouts())); - } -}; - -/** - * Refresh visualization of selected layouts. - */ -CustomMap.prototype.refreshSelectedLayouts = function() { - logger.debug("Refreshing layouts"); - var layouts = this.getSelectedLayouts(); - - // show layouts that should be visualized (resize or show them) - for (var i = 0; i < layouts.length; i++) { - var layoutId = layouts[i]; - if (this.layoutContainsOverlays(layoutId)) { - // resize element on the map - this.resizeSelectedLayout(layoutId, i, layouts.length); - } else { - this.showSelectedLayout(layoutId, i, layouts.length); - } - } - - // remove layouts that were - for ( var key in this.selectedLayoutOverlays) { - if (!this.selectedLayouts.hasOwnProperty(key) - || this.selectedLayouts[key] == false) { - if (this.layoutContainsOverlays(key)) { - this.hideSelectedLayout(key); - } - } - } - this.refreshInfoWindows(); -}; - -/** - * Hides layout from the map and all submaps - * - * @param layoutId - * identifier of a layout to hide - */ -CustomMap.prototype.hideSelectedLayout = function(layoutId) { - this._hideSelectedLayout(layoutId); - for (var i = 0; i < this.submaps.length; i++) { - this.submaps[i]._hideSelectedLayout(layoutId); - } -} - -/** - * Resize(refresh) layout on the map and all submaps. Resizing should be called - * when number of layouts to visualize change. - * - * @param layoutId - * identifier of layout to refresh - * @param index - * position of the layout in list of layouts that we visualize - * @param length - * number of layouts that we currently visualize - */ -CustomMap.prototype.resizeSelectedLayout = function(layoutId, index, length) { - logger.debug("Resize layout: " + layoutId); - this._resizeSelectedLayout(layoutId, index, length); - for (var i = 0; i < this.submaps.length; i++) { - this.submaps[i]._resizeSelectedLayout(layoutId, index, length); - } -} - -/** - * Show layout on the map and all submaps. - * - * @param layoutId - * identifier of layout to show - * @param index - * position of the layout in list of layouts that we visualize - * @param length - * number of layouts that we currently visualize - */ -CustomMap.prototype.showSelectedLayout = function(layoutId, index, length) { - logger.debug("Resize layout: " + layoutId); - this._showSelectedLayout(layoutId, index, length); - for (var i = 0; i < this.submaps.length; i++) { - this.submaps[i]._showSelectedLayout(layoutId, index, length); - } -} - -/** - * Adds information about reactions visible in the specific layout. - * - * @param layoutId - * identifier of the layout - * - * @param jsonAliases - * list of reactions in json format - * - */ -CustomMap.prototype.addReactionsForLayout = function(layoutId, jsonReactions) { - logger.debug("Adding reactions for layout: " + layoutId); - var reactions = JSON.parse(jsonReactions); - for (var i = 0; i < reactions.length; i++) { - var reaction = reactions[i]; - var model = this.getSubmodelById(reaction.modelId); - if (model != 'undefined' && model != null) { - model.mapModel.addReactionForLayout(layoutId, reaction); - } else { - logger.warn("Unknown model: " + reaction.modelId); - } - } - this.retrieveMissingReactions(); -} - -/** - * Adds information about reactions. - * - * @param jsonAliases - * list of reactions in json format - * - */ -CustomMap.prototype.addReactions = function(jsonReactions) { - var reactions = JSON.parse(jsonReactions); - for (var i = 0; i < reactions.length; i++) { - var reaction = reactions[i]; - var model = this.getSubmodelById(reaction.modelId); - if (model != 'undefined' && model != null) { - model.addReaction(reaction); - } else { - logger.warn("Unknown model: " + reaction.modelId); - } - } - this.callListeners("onAddReactions"); -} - -/** - * This function will ask server for reactions that should be visualized but the - * data is still missing on the client side. - */ -CustomMap.prototype.retrieveMissingReactions = function() { - var ids = []; - var missing = this.mapModel.getMissingReactionIds(); - for (var j = 0; j < missing.length; j++) { - ids.push([ this.getId(), missing[j] ]); - } - for (var i = 0; i < this.submaps.length; i++) { - missing = this.submaps[i].mapModel.getMissingReactionIds(); - for (var j = 0; j < missing.length; j++) { - ids.push([ this.submaps[i].getId(), missing[j] ]); - } - } - if (ids.length > 0) { - // load data from server about missing reactions - ServerConnector.retreiveLightReactions(ids); - } - if (!ServerConnector.isWaitingForData()) { - // if we already have everything then just refresh data to be visualized - this.refreshSelectedLayouts(); - //and close "loading" dialog (if opened) - GuiConnector.closeLoadingDialog(); - } -} - -/** - * This method checks if the layout contains any overlays (like AliasOverlay or - * ReactionOverlay) that is currently visible on the map. - * - * @param layoutId - * identifier of the layout - * @returns {Boolean}: <code>true</code> if the layout contains overlays to - * visualize, <code>false</code> otherwise - */ -CustomMap.prototype.layoutContainsOverlays = function(layoutId) { - - // first, check top map - if (this.selectedLayoutOverlays.hasOwnProperty(layoutId) - && this.selectedLayoutOverlays[layoutId].length > 0) { - return true; - } - - // now check all submaps - for (var i = 0; i < this.submaps.length; i++) { - if (this.submaps[i].initialized) { - if (this.submaps[i].selectedLayoutOverlays.hasOwnProperty(layoutId) - && this.submaps[i].selectedLayoutOverlays[layoutId].length > 0) { - return true; - } - } - } - return false; -} - -/** - * Refresh content of all {@link AliasInfoWindow} in this map and all submaps. - */ -CustomMap.prototype.refreshInfoWindows = function() { - this._refreshInfoWindows(); - // now check all submaps - for (var i = 0; i < this.submaps.length; i++) { - this.submaps[i]._refreshInfoWindows(); - } -} - -/** - * Opens {@link AliasInfoWindow} for an {@link Alias} in a given model/submodel. - * - * @param aliasId - * identifier of {@link Alias} - * @param modelId - * identifier of {@link AbstractCustomMap} - */ -CustomMap.prototype.openInfoWindowForAlias = function(aliasId, modelId) { - logger.debug("Opening info window for alias: " + aliasId + ", model: " - + modelId); - var model = this.getSubmodelById(modelId); - var alias = model.mapModel.getAliasById(aliasId); - - // if we have only simple version of the data then ask server for more details - if (alias == null || alias.completness == 'SIMPLE') { - logger.debug("Accessing full alias: " + aliasId); - var ids = [ [ modelId, aliasId ] ]; - ServerConnector.retreiveFullAliases(ids); - } - // open AliasInfoWindow in a right model - model._openInfoWindowForAlias(aliasId); -}; - -/** - * Renders markers, lines, etc. for elements highlighted in OverlayCollection. - * - * @param overlayCollection - * {@link OverlayCollection} to be processed - * @param fitBounds - * <code>true</code> if the borders should fit bounds after - * creating all elements - */ -CustomMap.prototype.renderOverlayCollection = function(overlayCollection, - fitBounds) { - var elements = overlayCollection.elements; - var missingElements = false; - - var boundsArray = []; - boundsArray[this.getId()] = new google.maps.LatLngBounds(); - for (var i = 0; i < this.submaps.length; i++) { - boundsArray[this.submaps[i].getId()] = new google.maps.LatLngBounds(); - } - - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - var model = this.getSubmodelById(element.modelId); - if (element.type == "ALIAS") { - if (overlayCollection.aliasMarkers[element.getId()] != null) { - logger.warn("More than one marker in " + overlayCollection.name - + " for alias " + element.getId() + ". Skipping duplicates."); - } else { - var aliasData = model.mapModel.getAliasById(element.getId()); - if (aliasData == null) { - model.mapModel.addMissingAliasId(element.getId()); - missingElements = true; - } - var marker = new AliasMarker(element.getId(), element.icon, aliasData, - model); - overlayCollection.aliasMarkers[element.getId()] = marker; - if (!missingElements) { - var bounds = marker.getBounds(); - boundsArray[element.modelId].extend(bounds.getNorthEast()); - boundsArray[element.modelId].extend(bounds.getSouthWest()); - } - } - } else if (element.type == "REACTION") { - var reactionData = model.mapModel.getReactionById(element.getId()); - if (reactionData == null) { - model.mapModel.addMissingReactionId(element.getId()); - missingElements = true; - } - 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; - if (!missingElements) { - var bounds = marker.getBounds(); - boundsArray[element.modelId].extend(bounds.getNorthEast()); - boundsArray[element.modelId].extend(bounds.getSouthWest()); - - } - } else if (element.type == "POINT") { - var pointData = model.mapModel.getPointDataByPoint(element.getPoint()); - var marker = new PointMarker(pointData, element.icon, model); - overlayCollection.pointMarkers[pointData.getId()] = marker; - if (!missingElements) { - var bounds = marker.getBounds(); - boundsArray[element.modelId].extend(bounds.getNorthEast()); - boundsArray[element.modelId].extend(bounds.getSouthWest()); - } - } else { - logger.warn("Unknown type of the element in overlay: " + element.type); - } - var infoWindow = this.getInfoWindowForIdentifiedElement(element); - if (infoWindow != null) { - this.retrieveOverlayDetailDataForElement(element, infoWindow - .getOverlayFullViewArray()); - this.updateInfoWindowForIdentifiedElement(element); - } - } - - if (missingElements) { - this.retrieveMissingReactions(); - this.retrieveMissingAliases(); - } else { - if (elements.length > 0 && fitBounds) { - for ( var mapId in boundsArray) { - if (boundsArray.hasOwnProperty(mapId)) { - var map = this.getSubmodelById(mapId).map; - var bounds = boundsArray[mapId]; - if (map != null && !bounds.isEmpty()) { - if (typeof map.fitBounds2 !== "undefined") { - map.fitBounds2(bounds); - } else { - map.fitBounds(bounds); - } - } - } - } - } - } -}; - -/** - * Creates and register listeners to be called on events: - * <ul> - * <li>onAddAliases</li> - * <li>onAddReactions</li> - * </ul> - */ -CustomMap.prototype.createClientServerListeners = function() { - this.registerListenerType("onAddAliases"); - this.registerListenerType("onAddReactions"); - - var refreshLayoutsFun = function(e) { - var self = e.object; - if (!ServerConnector.isWaitingForData()) { - self.refreshSelectedLayouts(); - //and close "loading" dialog (if opened) - GuiConnector.closeLoadingDialog(); - } - }; - - var refreshOverlaysFun = function(e) { - e.object.refreshMarkers(); - }; - - this.addListener("onAddAliases", refreshLayoutsFun); - this.addListener("onAddAliases", refreshOverlaysFun); - - this.addListener("onAddReactions", refreshLayoutsFun); - this.addListener("onAddReactions", refreshOverlaysFun); - -}; - -/** - * Opens {@link AbstractInfoWindow} for a marker. - * - * @param marker - * {@link AbstractMarker} for which info window should be opened - */ -CustomMap.prototype.openInfoWindowForMarker = function(marker) { - var modelId = marker.getCustomMap().getId(); - var markerId = marker.getId(); - var model = this.getSubmodelById(modelId); - logger.debug("Opening info window for " + marker.constructor.name + ": " - + markerId + ", model: " + modelId); - var elementType = marker.getType(); - if (marker instanceof AliasMarker) { - var alias = model.mapModel.getAliasById(markerId); - - // if we have only simple version of the data then ask server for more - // details - if (alias == null || alias.completness == 'SIMPLE') { - logger.debug("Accessing full alias: " + markerId); - var ids = [ [ modelId, markerId ] ]; - ServerConnector.retreiveFullAliases(ids); - } - } else if (marker instanceof PointMarker) { - // no special treatment for points - } else if (marker instanceof ReactionMarker) { - // no special treatment for reactions - } else { - logger.error("Unknown marker type: " + marker.constructor.name); - } - - // open AliasInfoWindow in a right model - model._openInfoWindowForMarker(marker); - - var infoWindow = model.returnInfoWindowForMarker(marker); - - var element = new IdentifiedElement({ - objectId : markerId, - modelId : modelId, - type : elementType - }); - - this.retrieveOverlayDetailDataForElement(element, infoWindow - .getOverlayFullViewArray()); - -}; - -/** - * Sends requestes to download detailed data about element in all - * {@link OverlayCollection}. - * - * @param element - * element for which we want to have detailed information - */ -CustomMap.prototype.retrieveOverlayDetailDataForElement = function(element, - general) { - if (general === undefined) { - logger.warn("general param is undefined!"); - general = []; - } - for ( var overlayName in this.overlayCollections) { - if (this.overlayCollections.hasOwnProperty(overlayName)) { - var overlay = this.overlayCollections[overlayName]; - - var generalRequest = general[overlayName]; - if (generalRequest === undefined) { - logger.warn( - "No information about general overlay request for overlay: ", - overlayName); - generalRequest = false; - } - generalRequest = generalRequest || !overlay.allowSearchById(); - - if (overlay.allowGeneralSearch() || overlay.allowSearchById()) { - if (overlay.isMissingDetailData(element, generalRequest)) { - ServerConnector.sendOverlayDetailDataRequest(overlayName, element, - generalRequest); - } - } - } - } -}; - -/** - * Updates info window identified by element given as a parameter. - * - * @param identifiedElement - * element for which info window should be updated - */ -CustomMap.prototype.updateInfoWindowForIdentifiedElement = function( - identifiedElement) { - var infoWindow = this.getInfoWindowForIdentifiedElement(identifiedElement); - if (infoWindow == null) { - return; - } else { - infoWindow.update(); - } -}; - -/** - * Returns data from all {@link OverlayCollection} for a given alias. - * - * @param alias - * {@link Alias} for which overlay data will be returned - * @param general - * if true then all elements will be returned, if false then only - * ones availble right now in the overlay - * @returns data from all {@link OverlayCollection} for a given alias - */ -CustomMap.prototype.getOverlayDataForAlias = function(alias, general) { - var identifiedElement = new IdentifiedElement(alias); - return this.getOverlayDataForIdentifiedElement(identifiedElement, general); -}; - -/** - * Returns data from all {@link OverlayCollection} for a given reaction. - * - * @param reaction - * {@link Reaction} for which overlay data will be returned - * @param general - * if true then all elements will be returned, if false then only - * ones availble right now in the overlay - * @returns data from all {@link OverlayCollection} for a given alias - */ -CustomMap.prototype.getOverlayDataForReaction = function(reaction, general) { - var identifiedElement = new IdentifiedElement(reaction); - return this.getOverlayDataForIdentifiedElement(identifiedElement, general); -}; - -/** - * Returns data from all {@link OverlayCollection} for a given {@link PointData} - * - * @param point - * {@link PointData} for which overlay data will be returned - * @returns data from all {@link OverlayCollection} for a given - * {@link PointData} - */ -CustomMap.prototype.getOverlayDataForPoint = function(point, general) { - var identifiedElement = new IdentifiedElement(point); - return this.getOverlayDataForIdentifiedElement(identifiedElement, general); -}; - -/** - * Returns data from all {@link OverlayCollection} for element identified by the - * parameter - * - * @param identifiedElement - * {@link IdentifiedElement} for which overlay data will be returned - * @returns data from all {@link OverlayCollection} for a given - * {@link IdentifiedElement} - */ -CustomMap.prototype.getOverlayDataForIdentifiedElement = function( - identifiedElement, general) { - if (general === undefined) { - logger.warn("general parameter must be defined"); - general = []; - } - var result = []; - for ( var overlayName in this.overlayCollections) { - if (this.overlayCollections.hasOwnProperty(overlayName)) { - var overlay = this.overlayCollections[overlayName]; - if (overlay.allowGeneralSearch() || overlay.allowSearchById()) { - var generalFlag = general[overlay.getName()]; - if (generalFlag === undefined) { - logger.warn("General flag for overlay: " + overlay.getName() - + " is not defined, assuming false"); - generalFlag = false; - } - result.push({ - overlay : overlay, - data : overlay.getDetailDataByIdentifiedElement(identifiedElement, - !overlay.allowSearchById() || generalFlag) - }); - } - } - } - return result; -}; - -/** - * Returns {@link AbstractInfoWindow} for element identified by the parameter. - * - * @param identifiedElement - * {@link IdentifiedElement} that determines for which element we - * want {@link AbstractInfoWindow} - * @returns {@link AbstractInfoWindow} for element identified by the parameter - */ -CustomMap.prototype.getInfoWindowForIdentifiedElement = function( - identifiedElement) { - var model = this.getSubmodelById(identifiedElement.modelId); - var infoWindow = null; - if (identifiedElement.type == "ALIAS") { - infoWindow = model.getAliasInfoWindowById(identifiedElement.getId()); - } else if (identifiedElement.type == "POINT") { - infoWindow = model.getPointInfoWindowById(identifiedElement.getId()); - } else if (identifiedElement.type == "REACTION") { - infoWindow = model.getReactionInfoWindowById(identifiedElement.getId()); - } else { - logger.error("Unknown type of IdentifiedElement: ", identifiedElement); - } - return infoWindow; -}; - -CustomMap.prototype.getActiveSubmapId = function() { - return this._activeSubmapId; -}; - -CustomMap.prototype.setActiveSubmapId = function(submapId) { - this._activeSubmapId = submapId; -}; - -CustomMap.prototype.updateAliasesForLayout = function(layoutId, jsonAliases) { - logger.debug("Updating aliases for layout: " + layoutId); - - // init layout data - if (this.mapModel.getLayoutDataById(layoutId) == null) { - this.mapModel.initLayoutData(layoutId); - for (var i = 0; i < this.submaps.length; i++) { - this.submaps[i].mapModel.initLayoutData(layoutId); - } - } - - var aliases = JSON.parse(jsonAliases); - for (var i = 0; i < aliases.length; i++) { - var alias = aliases[i]; - var model = this.getSubmodelById(alias.modelId); - if (model != 'undefined' && model != null) { - model.mapModel.updateAliasForLayout(layoutId, alias); - model.getAliasInfoWindowById(alias.idObject).update(); - } else { - logger.warn("Unknown model: " + alias.modelId); - } - } - - this.retrieveMissingAliases(); -}; - -CustomMap.prototype.getReferenceGenome = function(type, version) { - var result = null; - if (this._referenceGenome[type] == null) { - this._referenceGenome[type] = []; - } - if (this._referenceGenome[type][version] == null) { - ServerConnector.sendReferenceGenomeDetailRequest(type, version); - this._referenceGenome[type][version] = new ReferenceGenome(null); - return null; - } else { - return this._referenceGenome[type][version]; - } -}; - -CustomMap.prototype.updateReferenceGenome = function(type, version, jsonObj) { - if (this._referenceGenome[type] == null) { - this._referenceGenome[type] = []; - } - this._referenceGenome[type][version] = new ReferenceGenome(jsonObj); - this.refreshInfoWindows(); -} +/** + * Default constructor. + * + * @param globalMap + * google.maps.Map object representing the map + * @param configuration + * Configuration object representing our data in the map + * @param bigButtons + * boolean value determining if the buttons on the map should be big, + * and if the map is run on the touch interface + * @param hideDiv + * + */ +function CustomMap(options) { + if (!(options instanceof CustomMapOptions)) { + options = new CustomMapOptions(options); + } + AbstractCustomMap.call(this, options); + + // set config parameters + this.map = options.getMap(); + + if (options.isCustomTouchInterface()) { + this._touchInterface = new TouchMap(this); + } + + // create function that override primefaces fitBounds with default google + // implementation + var fitBounds = function(bounds) { + var tmp = this.fitBounds; + this.fitBounds = google.maps.Map.prototype.fitBounds; + this.fitBounds(bounds); + this.fitBounds = tmp; + }; + this.map.fitBounds2 = fitBounds; + + this.buttons = []; + + this.createSubmaps(); + + this.selectedLayouts = []; + + this.setupLayouts(); + + this.createBelt(); + + this.customizeGoogleMapView(); + + this.createMapChangedCallbacks(); + + this.createClientServerListeners(); + + this.overlayCollections = []; + + // which submap is active (where user made interaction for the last time) + this._activeSubmapId = null; + + this.initialized = true; + + // list of reference genomes + this._referenceGenome = []; + + ServerConnector.actualizeSessionData(); +} + +CustomMap.prototype = Object.create(AbstractCustomMap.prototype); + +CustomMap.prototype.constructor = CustomMap; + +CustomMap.prototype.createSubmaps = function() { + this.submaps = []; + for (var i = 0; i < this.getConfiguration().SUBMODELS.length; i++) { + this.submaps.push(new Submap(this, + this.getConfiguration().SUBMODELS[i].ID_MODEL)); + } +}; + +CustomMap.prototype.createLogo = function() { + + var logoControlDiv = document.createElement('DIV'); + var logo = document.createElement('IMG'); + var url = ServerConnector.getLogoImg(); + if (!/^(f|ht)tps?:\/\//i.test(url)) { + url = GuiConnector.getImgPrefix() + url; + } + logo.src = url; + logo.style.cursor = 'pointer'; + logo.style.width = "80px"; + logoControlDiv.appendChild(logo); + google.maps.event.addDomListener(logo, 'click', function() { + var win = window.open(ServerConnector.getLogoLink(), '_blank'); + win.focus(); + }); + logoControlDiv.index = 0; // used for ordering + this.map.controls[google.maps.ControlPosition.LEFT_BOTTOM] + .push(logoControlDiv); + + var logoControlDiv = document.createElement('DIV'); + logoControlDiv.style.padding = '5px'; + + var logo = document.createElement('IMG'); + logo.src = GuiConnector.getImgPrefix() + + GuiConnector.getLcsbLogoImg(this.bigButtons); + logo.style.cursor = 'pointer'; + logoControlDiv.appendChild(logo); + google.maps.event.addDomListener(logo, 'click', function() { + var win = window.open('http://wwwen.uni.lu/lcsb/', '_blank'); + win.focus(); + }); + + logoControlDiv.index = 1; // used for ordering + this.map.controls[google.maps.ControlPosition.RIGHT_BOTTOM] + .push(logoControlDiv); +}; + +CustomMap.prototype.createBelt = function() { + var self = this; + + this.divBelt = document.createElement('DIV'); + this.divBelt.className = "headerBelt"; + + var hideDivButton = document.createElement('DIV'); + hideDivButton.className = "headerHideDivButton"; + + var hideButton = document.createElement('button'); + hideButton.id = "hide_button"; + hideButton.className = "headerHideButton"; + hideButton.innerHTML = "<i class='fa fa-chevron-left'></i>"; + // when there is no div to hide we should allow hiding + if (self.getHideDiv() !== undefined) { + hideButton.onclick = (function() { + var button = hideButton; + var div = self.getHideDiv(); + + var left = $(PrimeFaces.escapeClientId(self.map.getDiv().id)).offset().left; + return function() { + if (button.innerHTML.indexOf('fa-chevron-left') > 0) { + button.innerHTML = "<i class='fa fa-chevron-right'></i>"; + div.style.display = 'none'; + self.map.getDiv().style.left = "0px"; + } else { + div.style.display = 'block'; + button.innerHTML = "<i class='fa fa-chevron-left'></i>"; + self.map.getDiv().style.left = left + "px"; + } + google.maps.event.trigger(self.map, 'resize'); + return false; + }; + })(); + } else { + hideButton.disabled = true; + logger.warn("Left panel hiding disabled"); + } + hideDivButton.appendChild(hideButton); + hideDivButton.index = 1; // used for ordering + this.divBelt.appendChild(hideDivButton); + + var controlText = document.createElement('div'); + controlText.className = "headerTextBold"; + controlText.innerHTML = this.getConfiguration().MAP_NAME; + this.divBelt.appendChild(controlText); + + this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(this.divBelt); +}; + +CustomMap.prototype.setLegendVisible = function(vis) { + if (vis) { + document.getElementById('legend').style.display = 'block'; + } else { + document.getElementById('legend').style.display = 'none'; + } +}; + +CustomMap.prototype.clearOverlays = function() { + for ( var overlayName in this.overlayCollections) { + if (this.overlayCollections.hasOwnProperty(overlayName)) { + var collection = this.overlayCollections[overlayName]; + this.clearOverlayCollection(collection); + } + } +}; + +CustomMap.prototype.refreshOverlays = function() { + for ( var overlayName in this.overlayCollections) { + if (this.overlayCollections.hasOwnProperty(overlayName)) { + var collection = this.overlayCollections[overlayName]; + collection.refresh(); + } + } +}; + +/** + * Removes all markers from {@link OverlayCollection}. + * + * @param collection + * {@link OverlayCollection} from which all markers should be removed + */ +CustomMap.prototype.clearOverlayCollection = function(collection) { + logger.debug("Clear collection: " + collection.name); + for ( var key in collection.aliasMarkers) { + if (collection.aliasMarkers.hasOwnProperty(key) + && collection.aliasMarkers[key] != null) { + collection.aliasMarkers[key].setMap(null); + } + } + + for ( var key in collection.pointMarkers) { + if (collection.pointMarkers.hasOwnProperty(key) + && collection.pointMarkers[key] != null) { + + collection.pointMarkers[key].setMap(null); + } + } + + for ( var key in collection.reactionMarkers) { + if (collection.reactionMarkers.hasOwnProperty(key) + && collection.reactionMarkers[key] != null) { + collection.reactionMarkers[key].setMap(null); + } + } + + collection.aliasMarkers = []; + collection.pointMarkers = []; + collection.reactionMarkers = []; +}; + +/** + * Updates data about visualized markers in {@link OverlayCollection}. + * + * @param overlayCollection + * {@link OverlayCollection} with new data to visualize + * @param fitBounds + * <code>true</code> id the map should fit bounds to the new + * elements after update, <code>false</code> otherwise + */ +CustomMap.prototype.updateOverlayCollection = function(overlayCollection, + fitBounds) { + this.clearOverlayCollection(overlayCollection); + this.renderOverlayCollection(overlayCollection, fitBounds); +}; + +/** + * This method open layout by a given layout identifier (string starting with + * 'cv' prefix) in a map and all submaps. + * + * @param identifier + * identifier of the layout to present + */ +CustomMap.prototype.openLayout = function(identifier) { + logger.debug("Opening layout: " + identifier); + + this.map.setMapTypeId(identifier); + + var index = null; + for (var i = 0; i < this.getConfiguration().MAPS.length; i++) { + if ('cv' + this.getConfiguration().MAPS[i].idObject == identifier) { + index = i; + } + } + if (index == null) { + logger.warn("Invalid layout identifier: " + identifier); + } + for (var i = 0; i < this.submaps.length; i++) { + this.submaps[i].openLayout('cv' + + this.submaps[i].getConfiguration().MAPS[index].idObject); + } +}; + +/** + * This method open layout by a given database identifier. + * + * @param identifier + * identifier of the layout to present + */ +CustomMap.prototype.openLayoutById = function(identifier) { + logger.debug("Opening layout: " + identifier); + var index = null; + for (var i = 0; i < configuration.MAPS.length; i++) { + if (configuration.MAPS[i].idObject == identifier) { + index = 'cv' + identifier; + } + } + + // if layout doesn't exist print error + if (index == null) { + alert("You have no privileges for selected layout"); + } else { + this.openLayout(index); + } +}; + +CustomMap.prototype.createMapMenu = function(layoutButtons) { + var selfMap = this; + + var buttons = []; + + // create a button for overview images when the image is available + if (this.getConfiguration().TOP_OVERVIEW_IMAGE != "undefined" + && this.getConfiguration().TOP_OVERVIEW_IMAGE != null) { + var submenuButtonDiv = document.createElement('button'); + buttons.push(submenuButtonDiv); + submenuButtonDiv.id = "overview_button"; + submenuButtonDiv.innerHTML = "<i class='fa fa-sitemap' style='font-size:18px; font-weight:400; padding-right:10px;'></i> SHOW OVERVIEW"; + submenuButtonDiv.className = "overview_button"; + submenuButtonDiv.onclick = (function() { + return function() { + selfMap.showOverview(); + return false; + }; + })(); + this.divBelt.appendChild(submenuButtonDiv); + } + + var rightHeaderMenu = document.createElement('div'); + rightHeaderMenu.className = "rightHeaderMenu"; + var submenuDiv = document.createElement('div'); + submenuDiv.className = "div4checkboxes"; + var submenuButtonDiv = document.createElement('input'); + submenuButtonDiv.type = "checkbox"; + submenuButtonDiv.name = "Comments"; + submenuButtonDiv.id = "comment_checkbox"; + submenuButtonDiv.onclick = (function() { + var selfButton = submenuButtonDiv; + return function() { + selfMap.showComments = selfButton.checked; + ServerConnector.setShowComments(selfButton.checked); + if (selfButton.checked) { + document.getElementById('refresh_comments_button').style.display = 'inline'; + } else { + document.getElementById('refresh_comments_button').style.display = 'none'; + } + selfMap.refreshComments(); + + }; + })(); + var element = document.createElement('label'); + element.innerHTML = "COMMENTS"; + element.setAttribute("for", "comment_checkbox"); + submenuDiv.appendChild(submenuButtonDiv); + submenuDiv.appendChild(element); + + var submenuButtonDiv = document.createElement('input'); + submenuButtonDiv.type = "checkbox"; + submenuButtonDiv.name = "Legend"; + submenuButtonDiv.id = "lengend_checkbox"; + submenuButtonDiv.onclick = (function() { + var selfButton = submenuButtonDiv; + return function() { + if (selfButton.checked) { + GuiConnector.showLegend(); + } else { + GuiConnector.hideLegend(); + } + }; + })(); + element = document.createElement('label'); + element.innerHTML = "LEGEND"; + element.setAttribute("for", "lengend_checkbox"); + submenuDiv.appendChild(submenuButtonDiv); + submenuDiv.appendChild(element); + + submenuButtonDiv = document.createElement('button'); + submenuButtonDiv.id = "refresh_comments_button"; + submenuButtonDiv.innerHTML = "<i class='fa fa-refresh' style='font-size:21px; font-weight:400;'></i>"; + submenuButtonDiv.className = "overview_button"; + submenuButtonDiv.style.display = 'none'; + submenuButtonDiv.onclick = (function() { + return function() { + selfMap.refreshComments(); + return false; + }; + })(); + submenuDiv.appendChild(submenuButtonDiv); + rightHeaderMenu.appendChild(submenuDiv); + + var submenuButtonDiv = document.createElement('button'); + buttons.push(submenuButtonDiv); + submenuButtonDiv.id = "clear_button"; + submenuButtonDiv.className = "overview_button"; + submenuButtonDiv.innerHTML = "<i class='fa fa-times' style='font-size:18px; font-weight:300; padding-right:10px;'></i> CLEAR"; + submenuButtonDiv.title = "Clear all queries"; + submenuButtonDiv.style.display = 'inline'; + submenuButtonDiv.onclick = (function() { + return function() { + selfMap.clearData(); + return false; + }; + })(); + rightHeaderMenu.appendChild(submenuButtonDiv); + + this.divBelt.appendChild(rightHeaderMenu); +}; + +CustomMap.prototype.registerSource = function(overlayCollection) { + this.overlayCollections[overlayCollection.name] = overlayCollection; + overlayCollection.aliasMarkers = []; + overlayCollection.pointMarkers = []; + overlayCollection.reactionMarkers = []; +}; + +CustomMap.prototype.refreshComments = function() { + for ( var overlayName in this.overlayCollections) { + if (this.overlayCollections.hasOwnProperty(overlayName) + && overlayName == "comment") { + var collection = this.overlayCollections[overlayName]; + collection.refresh(); + return; + } + } + throw "comment OverlayCollection not found"; +}; + +CustomMap.prototype.turnOnOffDrawing = function() { + var model = this.getSubmodelById(this.getActiveSubmapId()); + if (model != null) { + model._turnOnOffDrawing(); + } else { + throw "Cannot find submodel with id: " + this.getActiveSubmapId(); + } +}; + +CustomMap.prototype.clearData = function() { + this.clearOverlays(); + for ( var overlayName in this.overlayCollections) { + if (this.overlayCollections.hasOwnProperty(overlayName)) { + ServerConnector.sendClearRequest(overlayName); + } + } +}; + +CustomMap.prototype.refreshMarkers = function() { + logger.debug("Refresh Markers: "); + for ( var overlayName in this.overlayCollections) { + if (this.overlayCollections.hasOwnProperty(overlayName)) { + var collection = this.overlayCollections[overlayName]; + this.refreshOverlayMarkers(collection); + } + } +}; + +CustomMap.prototype.refreshOverlayMarkers = function(overlay) { + var self = this; + logger.debug("Refresh overlay: " + overlay.name); + var boundsArray = []; + boundsArray[this.getId()] = new google.maps.LatLngBounds(); + for (var i = 0; i < this.submaps.length; i++) { + boundsArray[this.submaps[i].getId()] = new google.maps.LatLngBounds(); + } + + var updated = false; + var stillMissing = false; + for ( var key in overlay.aliasMarkers) { + if (overlay.aliasMarkers.hasOwnProperty(key) + && overlay.aliasMarkers[key] != null) { + var alias = overlay.aliasMarkers[key]; + if (alias.getAliasData() == null) { + var aliasData = alias.getCustomMap().mapModel.getAliasById(alias + .getId()); + if (aliasData != null) { + alias.setAliasData(aliasData); + alias.init(); + alias.show(); + updated = true; + var bounds = alias.getBounds(); + boundsArray[alias.getCustomMap().getId()].extend(bounds + .getNorthEast()); + } else { + stillMissing = true; + logger.debug("Cannot show alias marker. Data is still not loaded..."); + } + } else { + var bounds = alias.getBounds(); + if (!this.isMarkerOptimization()) { + alias.hide(); + alias.show(); + } + boundsArray[alias.getCustomMap().getId()].extend(bounds.getNorthEast()); + boundsArray[alias.getCustomMap().getId()].extend(bounds.getSouthWest()); + } + } + } + + for ( var key in overlay.pointMarkers) { + if (overlay.pointMarkers.hasOwnProperty(key) + && overlay.pointMarkers[key] != null) { + var alias = overlay.pointMarkers[key]; + // we don't need to update this markers because thet data about + // visualization is + // already there + // alias.update(); + var bounds = alias.getBounds(); + if (!this.isMarkerOptimization()) { + alias.hide(); + alias.show(); + } + boundsArray[alias.getCustomMap().getId()].extend(bounds.getNorthEast()); + } + } + + for ( var key in overlay.reactionMarkers) { + if (overlay.reactionMarkers.hasOwnProperty(key) + && overlay.reactionMarkers[key] != null) { + var reactionOverlay = overlay.reactionMarkers[key]; + if (reactionOverlay.getReactionData() == null) { + var reactionData = reactionOverlay.getCustomMap().mapModel + .getReactionById(reactionOverlay.getId()); + if (reactionData != null) { + reactionOverlay.setReactionData(reactionData); + reactionOverlay.init(); + reactionOverlay.show(); + updated = true; + var bounds = reactionOverlay.getBounds(); + boundsArray[reactionOverlay.getCustomMap().getId()].extend(bounds + .getNorthEast()); + boundsArray[reactionOverlay.getCustomMap().getId()].extend(bounds + .getSouthWest()); + } else { + stillMissing = true; + logger + .debug("Cannot show reaction marker. Data is still not loaded..."); + } + } else { + var bounds = alias.getBounds(); + if (!this.isMarkerOptimization()) { + alias.hide(); + alias.show(); + } + boundsArray[alias.getCustomMap().getId()].extend(bounds.getNorthEast()); + boundsArray[alias.getCustomMap().getId()].extend(bounds.getSouthWest()); + } + + } + } + + if (!stillMissing && updated && overlay.fitBounds) { + for ( var mapId in boundsArray) { + if (boundsArray.hasOwnProperty(mapId)) { + var map = this.getSubmodelById(mapId).map; + var bounds = boundsArray[mapId]; + if (map != null && !bounds.isEmpty()) { + if (typeof map.fitBounds2 !== "undefined") { + map.fitBounds2(bounds); + } else { + map.fitBounds(bounds); + } + } + } + } + } +}; + +CustomMap.prototype.openSubmodel = function(id, htmlTag, jsVar) { + if (jsVar.submapControler == null) { + var submap = null; + for (var i = 0; i < this.submaps.length; i++) { + if (this.submaps[i].getId() == id) { + submap = this.submaps[i]; + } + } + if (submap == null) { + logger.error("Unknown submap for id: " + id); + } else { + submap.init(htmlTag, jsVar); + //we have to perform it on top map, because on submaps id is different + this.openLayout(this.map.getMapTypeId()); + + this.refreshOverlays(); + + // now we have to visualize layouts + var layouts = []; + + // get list of layouts + for ( var key in this.selectedLayouts) { + if (this.selectedLayouts.hasOwnProperty(key) + && this.selectedLayouts[key] == true) { + layouts.push(key); + } + } + + // show layouts that should be visualized (resize or show them) + for (var i = 0; i < layouts.length; i++) { + var layoutId = layouts[i]; + submap._showSelectedLayout(layoutId, i, layouts.length); + } + } + } + jsVar.show(); + +}; + +CustomMap.prototype.customizeGoogleMapView = function() { + var mapOptions = this.creatMapOptions(); + this.map.setOptions(mapOptions); + + this.createMapMenu(false); + + this.registerMapClickEvents(); + + this.createLogo(); + // this.createMapVersion(); + google.maps.event.trigger(this.map, 'resize'); + google.maps.event.trigger(this.map, 'maptypeid_changed'); + google.maps.event.trigger(this.map, 'projection_changed'); + + // center map and zoom in to fit into browser window + if (this.getConfiguration().fitMapBounds) { + var bounds = new google.maps.LatLngBounds(); + var point = new google.maps.LatLng( + this.getConfiguration().topLeftLatLng.lat, + this.getConfiguration().topLeftLatLng.lng); + bounds.extend(point); + + point = new google.maps.LatLng( + this.getConfiguration().bottomRightLatLng.lat, + this.getConfiguration().bottomRightLatLng.lng); + bounds.extend(point); + + if (typeof this.map.fitBounds2 !== "undefined") { + this.map.fitBounds2(bounds); + } else { + this.map.fitBounds(bounds); + } + } +}; + +CustomMap.prototype.setCenter = function(mapIdentifier, coordinates) { + if (this.getConfiguration().ID_MODEL == mapIdentifier) { + this.map.setCenter(coordinates); + } else { + GuiConnector.openDialog(mapIdentifier); + for (var i = 0; i < this.submaps.length; i++) { + if (this.submaps[i].getId() == mapIdentifier) { + if (coordinates instanceof google.maps.Point) { + coordinates = this.submaps[i].fromPointToLatLng(coordinates); + } + this.submaps[i].map.setCenter(coordinates); + } + } + } +}; + +CustomMap.prototype.setZoom = function(mapIdentifier, zoom) { + if (this.getConfiguration().ID_MODEL == mapIdentifier) { + this.map.setZoom(zoom); + } else { + GuiConnector.openDialog(mapIdentifier); + for (var i = 0; i < this.submaps.length; i++) { + if (this.submaps[i].getId() == mapIdentifier) { + this.submaps[i].map.setZoom(zoom); + } + } + } +}; + +/** + * Creates listeners for google.maps.Map object that will actualize the data in + * user session. + */ +CustomMap.prototype.createMapChangedCallbacks = function() { + var customMapSelf = this; + // listener for changing zoom level + google.maps.event.addListener(this.map, 'zoom_changed', function() { + ServerConnector.setZoomLevel(customMapSelf.map.getZoom()); + ServerConnector.actualizeSessionData(); + }); + + // if we have zoom level data stored in session then restore it + var level = ServerConnector.getZoomLevel(); + if (parseInt(level) > 0) { + level = parseInt(level); + this.map.setZoom(level); + } else { + ServerConnector.setZoomLevel(customMapSelf.map.getZoom()); + } + + // listener for changing location of the map (moving left/reght/top/bottom + google.maps.event.addListener(this.map, 'center_changed', function() { + var coord = customMapSelf.map.getCenter(); + var point = customMapSelf.fromLatLngToPoint(coord); + ServerConnector.setCenterCoordinateX(point.x); + ServerConnector.setCenterCoordinateY(point.y); + ServerConnector.actualizeSessionData(); + }); + + // if we have coordinate data stored in session then restore it + var x = ServerConnector.getCenterCoordinateX(); + var y = ServerConnector.getCenterCoordinateY(); + if (!isNaN(x) && !isNaN(y)) { + var point = new google.maps.Point(x, y); + var coord = customMapSelf.fromPointToLatLng(point); + customMapSelf.map.setCenter(coord); + } + + // listener for changing type of layout + google.maps.event.addListener(this.map, 'maptypeid_changed', function() { + ServerConnector.setSelectedLayout(customMapSelf.map.getMapTypeId()); + ServerConnector.actualizeParams(); + }); + + // if we have type of layout stored in the session then restore it + var mapType = ServerConnector.getSelectedLayout(); + if (mapType != "" && mapType != null) { + this.openLayout(mapType); + } +}; + +/** + * Returns submodel (or this model) by identfier of the model. + * + * @param identifier + * identifier of the submodel + * @returns submodel (or this model) with given identfier of the model + */ +CustomMap.prototype.getSubmodelById = function(identifier) { + if (this.getId() == identifier) { + return this; + } + for (var i = 0; i < this.submaps.length; i++) { + if (this.submaps[i].getId() == identifier) { + return this.submaps[i]; + } + } + return null; +}; + +CustomMap.prototype.removeSelection = function() { + var model = this.getSubmodelById(this.getActiveSubmapId()); + if (model != null) { + model._removeSelection(); + } else { + throw "Cannot find submodel with id: " + this.getActiveSubmapId(); + } +}; + +/** + * This method will hide google map view and will present single image overview + * of the data. + */ +CustomMap.prototype.showOverview = function(overviewImageId) { + overviewDialog.syncWindowResize(); + if (this.getOverviewDiv() == "undefined" || this.getOverviewDiv() == null) { + logger.warn("Cannot show overview, because overview div is undefined"); + } else { + logger.debug("Show overview"); + overviewDialog.show(); + + // resize dialog + var htmlTag = GuiConnector.getOverviewHtmlTag(); + + var width = Math.floor(window.innerWidth * 2 / 3); + var height = Math.floor(window.innerHeight * 2 / 3); + + htmlTag.style.height = (height + 50) + "px"; + htmlTag.style.width = (width + 20) + "px"; + + var self = this; + + // remove all child nodes from overview div + while (this.getOverviewDiv().hasChildNodes()) { + this.getOverviewDiv().removeChild(this.getOverviewDiv().lastChild); + } + + if (overviewImageId == "undefined" || overviewImageId == null) { + this.overviewImage = this.getConfiguration().TOP_OVERVIEW_IMAGE; + } else { + this.overviewImage = null; + for (var i = 0; i < this.getConfiguration().OVERVIEW_IMAGES.length; i++) { + if (this.getConfiguration().OVERVIEW_IMAGES[i].idObject == overviewImageId) { + this.overviewImage = this.getConfiguration().OVERVIEW_IMAGES[i]; + } + } + + if (this.overviewImage == null) { + logger.warn("Unknown overview image with id = " + overviewImageId); + this.overviewImage = this.getConfiguration().TOP_OVERVIEW_IMAGE; + } + } + + // add image to overview div + this.overviewImageTag = document.createElement("IMG"); + this.overviewImageTag.src = "../map_images/" + this.overviewImage.filename; + this.getOverviewDiv().appendChild(this.overviewImageTag); + + var ratio = 1.0; + + // check how image should be resized to fit dialog and resize it manually!!! + if (width / this.overviewImage.width > height / this.overviewImage.height) { + this.overviewImageTag.style.height = height + "px"; + ratio = height / this.overviewImage.height; + width = this.overviewImage.width * ratio; + + htmlTag.style.width = (width + 20) + "px"; + } else { + this.overviewImageTag.style.width = width + "px"; + ratio = width / this.overviewImage.width; + height = this.overviewImage.height * ratio; + + htmlTag.style.height = (height + 50) + "px"; + } + + // center dialog + overviewDialog.jq.css("top", Math.max(0, + (($(window).height() - overviewDialog.jq.outerHeight()) / 2) + + $(window).scrollTop()) + + "px"); + overviewDialog.jq.css("left", Math.max(0, + (($(window).width() - overviewDialog.jq.outerWidth()) / 2) + + $(window).scrollLeft()) + + "px"); + + // on click event (what should happen when we click on the image) + var onclickevent = function getClickPosition(e) { + var parentPosition = getPosition(e.currentTarget); + var xPosition = e.clientX - parentPosition.x; + var yPosition = e.clientY - parentPosition.y; + + var imgWidth = self.overviewImageTag.offsetWidth; + + var currentRatio = imgWidth / self.overviewImage.width; + + var xNormal = xPosition / currentRatio; + var yNormal = yPosition / currentRatio; + var point = { + x : xNormal, + y : yNormal + }; + + var link = null; + for (var i = 0; i < self.overviewImage.links.length; i++) { + if (pointInsidePolygon(point, self.overviewImage.links[i].polygon)) { + if (link == null) { + link = self.overviewImage.links[i]; + } else { + logger.warn("More than one link found. Skipping"); + } + } + } + if (link != null) { + if (link.type == "OverviewModelLink") { + logger.debug("Opening model from overview. ModelId: " + + link.modelLinkId); + logger.debug("link coordinates [" + link.idObject + "]: " + + link.latLng); + // TODO min zoom value can be different for every map, it should be + // changed in the future + self.showModel(link.modelLinkId, link.latLng, link.zoomLevel + + self.getConfiguration().MIN_ZOOM); + overviewDialog.hide(); + } else if (link.type == "OverviewImageLink") { + logger.debug("Opening image from overview. ImageId: " + + link.imageLinkId); + self.showOverview(link.imageLinkId); + } else if (link.type == "OverviewSearchLink") { + logger.debug("Sending search query. Query: " + link.query); + searchPanel.search(link.query); + overviewDialog.hide(); + } else { + logger.warn("Unknown type of link: " + link.type + + ". Don't know what to do... LinkId: " + link.idObject); + } + } + }; + + this.overviewImageTag.onclick = onclickevent; + + // resize canvas where on mouse over highligh will appear + var canvas = document.getElementById("canvasDebug"); + canvas.width = width; + canvas.height = height; + canvas.onclick = onclickevent; + + // in debug mode draw clickable shapes + if (DEBUG_ON) { + var ctx = canvas.getContext("2d"); + // clear canvas + ctx.clearRect(0, 0, canvas.width, canvas.height); + for (var i = 0; i < this.overviewImage.links.length; i++) { + ctx.beginPath(); + var polygon = this.overviewImage.links[i].polygon; + for (var j = 0; j < polygon.length; j++) { + var x = polygon[j].x * ratio; + var y = polygon[j].y * ratio; + ctx.moveTo(x, y); + x = polygon[(j + 1) % polygon.length].x * ratio; + y = polygon[(j + 1) % polygon.length].y * ratio; + ctx.lineTo(x, y); + } + ctx.stroke(); + } + } + + this.overviewImage.mousePos = { + x : 0, + y : 0 + }; + + // this listener should be called when mouse moves over image, it purpose is + // to change coursor to pointer when mouse enters clickable polygon and back + // to normal when mouse leaves such region + var onmousemove = function getMouseOverPosition(e) { + var position = getPosition(e.currentTarget); + position.x = e.clientX - position.x; + position.y = e.clientY - position.y; + + var imgWidth = self.overviewImageTag.offsetWidth; + + var currentRatio = imgWidth / self.overviewImage.width; + + var xNormal = position.x / currentRatio; + var yNormal = position.y / currentRatio; + var point = { + x : xNormal, + y : yNormal + }; + + if (self.overviewImage.mousePos.x != position.x + || self.overviewImage.mousePos.y != position.y) { + self.overviewImage.mousePos = position; + var link = null; + for (var i = 0; i < self.overviewImage.links.length; i++) { + if (pointInsidePolygon(point, self.overviewImage.links[i].polygon)) { + link = self.overviewImage.links[i]; + } + } + if (link == null) { + e.currentTarget.style.cursor = "auto"; + } else { + e.currentTarget.style.cursor = "pointer"; + } + } + }; + + // onmousemove listener should be assigned to canvas (which is on top of the + // image) and overviewimage (just in case something went wrong with resizing + // canvas) + canvas.onmousemove = onmousemove; + this.overviewImageTag.onmousemove = onmousemove; + } +}; + +CustomMap.prototype.showModel = function(id, point, zoomLevel) { + if (point != "undefined") { + this.setCenter(id, point); + } else { + logger.warn("Center point undefined..."); + } + if (zoomLevel != "undefined") { + this.setZoom(id, zoomLevel); + } else { + logger.warn("Zoom level undefined..."); + } +}; + +/** + * Adds information about aliases visible in the specific layout. + * + * @param layoutId + * identifier of the layout + * + * @param jsonAliases + * list of aliases in json format + * + */ +CustomMap.prototype.addAliasesForLayout = function(layoutId, jsonAliases) { + logger.debug("Adding aliases for layout: " + layoutId); + + // init layout data + if (this.mapModel.getLayoutDataById(layoutId) == null) { + this.mapModel.initLayoutData(layoutId); + for (var i = 0; i < this.submaps.length; i++) { + this.submaps[i].mapModel.initLayoutData(layoutId); + } + } + + var aliases = JSON.parse(jsonAliases); + for (var i = 0; i < aliases.length; i++) { + var alias = aliases[i]; + var model = this.getSubmodelById(alias.modelId); + if (model != 'undefined' && model != null) { + model.mapModel.addAliasForLayout(layoutId, alias); + } else { + logger.warn("Unknown model: " + alias.modelId); + } + } + + this.retrieveMissingAliases(); +} + +/** + * Adds information about aliases. + * + * @param jsonAliases + * list of aliases in json format + * + */ +CustomMap.prototype.addAliases = function(aliases) { + for (var i = 0; i < aliases.length; i++) { + var alias = aliases[i]; + var model = this.getSubmodelById(alias.modelId); + if (model != 'undefined' && model != null) { + model.addAlias(alias); + } else { + logger.warn("Unknown model: " + alias.modelId); + } + } + this.callListeners("onAddAliases"); +} + +/** + * This function will ask server for aliases that should be visualized but the + * data is still missing on the client side. + */ +CustomMap.prototype.retrieveMissingAliases = function() { + var ids = []; + var missing = this.mapModel.getMissingAliasIds(); + for (var j = 0; j < missing.length; j++) { + ids.push([ this.getId(), missing[j] ]); + } + for (var i = 0; i < this.submaps.length; i++) { + missing = this.submaps[i].mapModel.getMissingAliasIds(); + for (var j = 0; j < missing.length; j++) { + ids.push([ this.submaps[i].getId(), missing[j] ]); + } + } + if (ids.length > 0) { + // load data from server about missing aliases + ServerConnector.retreiveLightAliases(ids); + } + if (!ServerConnector.isWaitingForData()) { + // if we already have everything then just refresh data to be visualized + this.refreshSelectedLayouts(); + //and close "loading" dialog + GuiConnector.closeLoadingDialog(); + } +} + +/** + * Adds layout to be visualized. + * + * @param identifier + * identifier of the layout that should be included in visualization + */ +CustomMap.prototype.addSelectedLayout = function(identifier, name) { + logger.debug("Selecting layout: " + identifier); + + if (this.selectedLayouts[identifier] == true) { + logger.warn("Layout " + identifier + " already selected"); + } else { + this.selectedLayouts[identifier] = true; + + // open dialog with info that we are loading data (it takes some time for + // bigger layouts on big maps) + GuiConnector.openLoadingDialog(); + + // if we don't have information about this layout then download it + if (this.mapModel.getLayoutDataById(identifier) == null) { + // initialize what we can on client side + this.mapModel.initLayoutData(identifier, name); + for (var i = 0; i < this.submaps.length; i++) { + this.submaps[i].mapModel.initLayoutData(identifier, name); + } + + // load data from server about this layout + ServerConnector.retreiveActiveAliasesForLayout(identifier); + + // load data from server about this layout + ServerConnector.retreiveActiveReactionsForLayout(identifier); + } + if (!ServerConnector.isWaitingForData()) { + // if we already loaded the data then just visualize it + this.refreshSelectedLayouts(); + //and close "loading" dialog (if opened) + GuiConnector.closeLoadingDialog(); + } + // if we have to load data from server then open info window should be + // opened + ServerConnector + .setVisibleLayouts(JSON.stringify(this.getSelectedLayouts())); + + } +}; + +/** + * Returns list of layouts that are selected and visualized by javascript. + * + * @return array with a list of selected layotus + * + */ +CustomMap.prototype.getSelectedLayouts = function() { + var layouts = []; + + // get list of layouts + for ( var key in this.selectedLayouts) { + if (this.selectedLayouts.hasOwnProperty(key) + && this.selectedLayouts[key] == true) { + layouts.push(key); + } + } + return layouts; +} + +/** + * Removes layout from visualization. + * + * @param identifier + * identifier of layout to remove + * + */ +CustomMap.prototype.removeSelectedLayout = function(identifier) { + logger.debug("Removing layout: " + identifier); + + if (this.selectedLayouts[identifier] != true) { + logger.warn("Layout " + identifier + " is not selected"); + } else { + this.selectedLayouts[identifier] = false; + this.refreshSelectedLayouts(); + ServerConnector + .setVisibleLayouts(JSON.stringify(this.getSelectedLayouts())); + } +}; + +/** + * Refresh visualization of selected layouts. + */ +CustomMap.prototype.refreshSelectedLayouts = function() { + logger.debug("Refreshing layouts"); + var layouts = this.getSelectedLayouts(); + + // show layouts that should be visualized (resize or show them) + for (var i = 0; i < layouts.length; i++) { + var layoutId = layouts[i]; + if (this.layoutContainsOverlays(layoutId)) { + // resize element on the map + this.resizeSelectedLayout(layoutId, i, layouts.length); + } else { + this.showSelectedLayout(layoutId, i, layouts.length); + } + } + + // remove layouts that were + for ( var key in this.selectedLayoutOverlays) { + if (!this.selectedLayouts.hasOwnProperty(key) + || this.selectedLayouts[key] == false) { + if (this.layoutContainsOverlays(key)) { + this.hideSelectedLayout(key); + } + } + } + this.refreshInfoWindows(); +}; + +/** + * Hides layout from the map and all submaps + * + * @param layoutId + * identifier of a layout to hide + */ +CustomMap.prototype.hideSelectedLayout = function(layoutId) { + this._hideSelectedLayout(layoutId); + for (var i = 0; i < this.submaps.length; i++) { + this.submaps[i]._hideSelectedLayout(layoutId); + } +} + +/** + * Resize(refresh) layout on the map and all submaps. Resizing should be called + * when number of layouts to visualize change. + * + * @param layoutId + * identifier of layout to refresh + * @param index + * position of the layout in list of layouts that we visualize + * @param length + * number of layouts that we currently visualize + */ +CustomMap.prototype.resizeSelectedLayout = function(layoutId, index, length) { + logger.debug("Resize layout: " + layoutId); + this._resizeSelectedLayout(layoutId, index, length); + for (var i = 0; i < this.submaps.length; i++) { + this.submaps[i]._resizeSelectedLayout(layoutId, index, length); + } +} + +/** + * Show layout on the map and all submaps. + * + * @param layoutId + * identifier of layout to show + * @param index + * position of the layout in list of layouts that we visualize + * @param length + * number of layouts that we currently visualize + */ +CustomMap.prototype.showSelectedLayout = function(layoutId, index, length) { + logger.debug("Resize layout: " + layoutId); + this._showSelectedLayout(layoutId, index, length); + for (var i = 0; i < this.submaps.length; i++) { + this.submaps[i]._showSelectedLayout(layoutId, index, length); + } +} + +/** + * Adds information about reactions visible in the specific layout. + * + * @param layoutId + * identifier of the layout + * + * @param jsonAliases + * list of reactions in json format + * + */ +CustomMap.prototype.addReactionsForLayout = function(layoutId, jsonReactions) { + logger.debug("Adding reactions for layout: " + layoutId); + var reactions = JSON.parse(jsonReactions); + for (var i = 0; i < reactions.length; i++) { + var reaction = reactions[i]; + var model = this.getSubmodelById(reaction.modelId); + if (model != 'undefined' && model != null) { + model.mapModel.addReactionForLayout(layoutId, reaction); + } else { + logger.warn("Unknown model: " + reaction.modelId); + } + } + this.retrieveMissingReactions(); +} + +/** + * Adds information about reactions. + * + * @param jsonAliases + * list of reactions in json format + * + */ +CustomMap.prototype.addReactions = function(jsonReactions) { + var reactions = JSON.parse(jsonReactions); + for (var i = 0; i < reactions.length; i++) { + var reaction = reactions[i]; + var model = this.getSubmodelById(reaction.modelId); + if (model != 'undefined' && model != null) { + model.addReaction(reaction); + } else { + logger.warn("Unknown model: " + reaction.modelId); + } + } + this.callListeners("onAddReactions"); +} + +/** + * This function will ask server for reactions that should be visualized but the + * data is still missing on the client side. + */ +CustomMap.prototype.retrieveMissingReactions = function() { + var ids = []; + var missing = this.mapModel.getMissingReactionIds(); + for (var j = 0; j < missing.length; j++) { + ids.push([ this.getId(), missing[j] ]); + } + for (var i = 0; i < this.submaps.length; i++) { + missing = this.submaps[i].mapModel.getMissingReactionIds(); + for (var j = 0; j < missing.length; j++) { + ids.push([ this.submaps[i].getId(), missing[j] ]); + } + } + if (ids.length > 0) { + // load data from server about missing reactions + ServerConnector.retreiveLightReactions(ids); + } + if (!ServerConnector.isWaitingForData()) { + // if we already have everything then just refresh data to be visualized + this.refreshSelectedLayouts(); + //and close "loading" dialog (if opened) + GuiConnector.closeLoadingDialog(); + } +} + +/** + * This method checks if the layout contains any overlays (like AliasOverlay or + * ReactionOverlay) that is currently visible on the map. + * + * @param layoutId + * identifier of the layout + * @returns {Boolean}: <code>true</code> if the layout contains overlays to + * visualize, <code>false</code> otherwise + */ +CustomMap.prototype.layoutContainsOverlays = function(layoutId) { + + // first, check top map + if (this.selectedLayoutOverlays.hasOwnProperty(layoutId) + && this.selectedLayoutOverlays[layoutId].length > 0) { + return true; + } + + // now check all submaps + for (var i = 0; i < this.submaps.length; i++) { + if (this.submaps[i].initialized) { + if (this.submaps[i].selectedLayoutOverlays.hasOwnProperty(layoutId) + && this.submaps[i].selectedLayoutOverlays[layoutId].length > 0) { + return true; + } + } + } + return false; +} + +/** + * Refresh content of all {@link AliasInfoWindow} in this map and all submaps. + */ +CustomMap.prototype.refreshInfoWindows = function() { + this._refreshInfoWindows(); + // now check all submaps + for (var i = 0; i < this.submaps.length; i++) { + this.submaps[i]._refreshInfoWindows(); + } +} + +/** + * Opens {@link AliasInfoWindow} for an {@link Alias} in a given model/submodel. + * + * @param aliasId + * identifier of {@link Alias} + * @param modelId + * identifier of {@link AbstractCustomMap} + */ +CustomMap.prototype.openInfoWindowForAlias = function(aliasId, modelId) { + logger.debug("Opening info window for alias: " + aliasId + ", model: " + + modelId); + var model = this.getSubmodelById(modelId); + var alias = model.mapModel.getAliasById(aliasId); + + // if we have only simple version of the data then ask server for more details + if (alias == null || alias.completness == 'SIMPLE') { + logger.debug("Accessing full alias: " + aliasId); + var ids = [ [ modelId, aliasId ] ]; + ServerConnector.retreiveFullAliases(ids); + } + // open AliasInfoWindow in a right model + model._openInfoWindowForAlias(aliasId); +}; + +/** + * Renders markers, lines, etc. for elements highlighted in OverlayCollection. + * + * @param overlayCollection + * {@link OverlayCollection} to be processed + * @param fitBounds + * <code>true</code> if the borders should fit bounds after + * creating all elements + */ +CustomMap.prototype.renderOverlayCollection = function(overlayCollection, + fitBounds) { + var elements = overlayCollection.elements; + var missingElements = false; + + var boundsArray = []; + boundsArray[this.getId()] = new google.maps.LatLngBounds(); + for (var i = 0; i < this.submaps.length; i++) { + boundsArray[this.submaps[i].getId()] = new google.maps.LatLngBounds(); + } + + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + var model = this.getSubmodelById(element.modelId); + if (element.type == "ALIAS") { + if (overlayCollection.aliasMarkers[element.getId()] != null) { + logger.warn("More than one marker in " + overlayCollection.name + + " for alias " + element.getId() + ". Skipping duplicates."); + } else { + var aliasData = model.mapModel.getAliasById(element.getId()); + if (aliasData == null) { + model.mapModel.addMissingAliasId(element.getId()); + missingElements = true; + } + var marker = new AliasMarker(element.getId(), element.icon, aliasData, + model); + overlayCollection.aliasMarkers[element.getId()] = marker; + if (!missingElements) { + var bounds = marker.getBounds(); + boundsArray[element.modelId].extend(bounds.getNorthEast()); + boundsArray[element.modelId].extend(bounds.getSouthWest()); + } + } + } else if (element.type == "REACTION") { + var reactionData = model.mapModel.getReactionById(element.getId()); + if (reactionData == null) { + model.mapModel.addMissingReactionId(element.getId()); + missingElements = true; + } + 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; + if (!missingElements) { + var bounds = marker.getBounds(); + boundsArray[element.modelId].extend(bounds.getNorthEast()); + boundsArray[element.modelId].extend(bounds.getSouthWest()); + + } + } else if (element.type == "POINT") { + var pointData = model.mapModel.getPointDataByPoint(element.getPoint()); + var marker = new PointMarker(pointData, element.icon, model); + overlayCollection.pointMarkers[pointData.getId()] = marker; + if (!missingElements) { + var bounds = marker.getBounds(); + boundsArray[element.modelId].extend(bounds.getNorthEast()); + boundsArray[element.modelId].extend(bounds.getSouthWest()); + } + } else { + logger.warn("Unknown type of the element in overlay: " + element.type); + } + var infoWindow = this.getInfoWindowForIdentifiedElement(element); + if (infoWindow != null) { + this.retrieveOverlayDetailDataForElement(element, infoWindow + .getOverlayFullViewArray()); + this.updateInfoWindowForIdentifiedElement(element); + } + } + + if (missingElements) { + this.retrieveMissingReactions(); + this.retrieveMissingAliases(); + } else { + if (elements.length > 0 && fitBounds) { + for ( var mapId in boundsArray) { + if (boundsArray.hasOwnProperty(mapId)) { + var map = this.getSubmodelById(mapId).map; + var bounds = boundsArray[mapId]; + if (map != null && !bounds.isEmpty()) { + if (typeof map.fitBounds2 !== "undefined") { + map.fitBounds2(bounds); + } else { + map.fitBounds(bounds); + } + } + } + } + } + } +}; + +/** + * Creates and register listeners to be called on events: + * <ul> + * <li>onAddAliases</li> + * <li>onAddReactions</li> + * </ul> + */ +CustomMap.prototype.createClientServerListeners = function() { + this.registerListenerType("onAddAliases"); + this.registerListenerType("onAddReactions"); + + var refreshLayoutsFun = function(e) { + var self = e.object; + if (!ServerConnector.isWaitingForData()) { + self.refreshSelectedLayouts(); + //and close "loading" dialog (if opened) + GuiConnector.closeLoadingDialog(); + } + }; + + var refreshOverlaysFun = function(e) { + e.object.refreshMarkers(); + }; + + this.addListener("onAddAliases", refreshLayoutsFun); + this.addListener("onAddAliases", refreshOverlaysFun); + + this.addListener("onAddReactions", refreshLayoutsFun); + this.addListener("onAddReactions", refreshOverlaysFun); + +}; + +/** + * Opens {@link AbstractInfoWindow} for a marker. + * + * @param marker + * {@link AbstractMarker} for which info window should be opened + */ +CustomMap.prototype.openInfoWindowForMarker = function(marker) { + var modelId = marker.getCustomMap().getId(); + var markerId = marker.getId(); + var model = this.getSubmodelById(modelId); + logger.debug("Opening info window for " + marker.constructor.name + ": " + + markerId + ", model: " + modelId); + var elementType = marker.getType(); + if (marker instanceof AliasMarker) { + var alias = model.mapModel.getAliasById(markerId); + + // if we have only simple version of the data then ask server for more + // details + if (alias == null || alias.completness == 'SIMPLE') { + logger.debug("Accessing full alias: " + markerId); + var ids = [ [ modelId, markerId ] ]; + ServerConnector.retreiveFullAliases(ids); + } + } else if (marker instanceof PointMarker) { + // no special treatment for points + } else if (marker instanceof ReactionMarker) { + // no special treatment for reactions + } else { + logger.error("Unknown marker type: " + marker.constructor.name); + } + + // open AliasInfoWindow in a right model + model._openInfoWindowForMarker(marker); + + var infoWindow = model.returnInfoWindowForMarker(marker); + + var element = new IdentifiedElement({ + objectId : markerId, + modelId : modelId, + type : elementType + }); + + this.retrieveOverlayDetailDataForElement(element, infoWindow + .getOverlayFullViewArray()); + +}; + +/** + * Sends requestes to download detailed data about element in all + * {@link OverlayCollection}. + * + * @param element + * element for which we want to have detailed information + */ +CustomMap.prototype.retrieveOverlayDetailDataForElement = function(element, + general) { + if (general === undefined) { + logger.warn("general param is undefined!"); + general = []; + } + for ( var overlayName in this.overlayCollections) { + if (this.overlayCollections.hasOwnProperty(overlayName)) { + var overlay = this.overlayCollections[overlayName]; + + var generalRequest = general[overlayName]; + if (generalRequest === undefined) { + logger.warn( + "No information about general overlay request for overlay: ", + overlayName); + generalRequest = false; + } + generalRequest = generalRequest || !overlay.allowSearchById(); + + if (overlay.allowGeneralSearch() || overlay.allowSearchById()) { + if (overlay.isMissingDetailData(element, generalRequest)) { + ServerConnector.sendOverlayDetailDataRequest(overlayName, element, + generalRequest); + } + } + } + } +}; + +/** + * Updates info window identified by element given as a parameter. + * + * @param identifiedElement + * element for which info window should be updated + */ +CustomMap.prototype.updateInfoWindowForIdentifiedElement = function( + identifiedElement) { + var infoWindow = this.getInfoWindowForIdentifiedElement(identifiedElement); + if (infoWindow == null) { + return; + } else { + infoWindow.update(); + } +}; + +/** + * Returns data from all {@link OverlayCollection} for a given alias. + * + * @param alias + * {@link Alias} for which overlay data will be returned + * @param general + * if true then all elements will be returned, if false then only + * ones availble right now in the overlay + * @returns data from all {@link OverlayCollection} for a given alias + */ +CustomMap.prototype.getOverlayDataForAlias = function(alias, general) { + var identifiedElement = new IdentifiedElement(alias); + return this.getOverlayDataForIdentifiedElement(identifiedElement, general); +}; + +/** + * Returns data from all {@link OverlayCollection} for a given reaction. + * + * @param reaction + * {@link Reaction} for which overlay data will be returned + * @param general + * if true then all elements will be returned, if false then only + * ones availble right now in the overlay + * @returns data from all {@link OverlayCollection} for a given alias + */ +CustomMap.prototype.getOverlayDataForReaction = function(reaction, general) { + var identifiedElement = new IdentifiedElement(reaction); + return this.getOverlayDataForIdentifiedElement(identifiedElement, general); +}; + +/** + * Returns data from all {@link OverlayCollection} for a given {@link PointData} + * + * @param point + * {@link PointData} for which overlay data will be returned + * @returns data from all {@link OverlayCollection} for a given + * {@link PointData} + */ +CustomMap.prototype.getOverlayDataForPoint = function(point, general) { + var identifiedElement = new IdentifiedElement(point); + return this.getOverlayDataForIdentifiedElement(identifiedElement, general); +}; + +/** + * Returns data from all {@link OverlayCollection} for element identified by the + * parameter + * + * @param identifiedElement + * {@link IdentifiedElement} for which overlay data will be returned + * @returns data from all {@link OverlayCollection} for a given + * {@link IdentifiedElement} + */ +CustomMap.prototype.getOverlayDataForIdentifiedElement = function( + identifiedElement, general) { + if (general === undefined) { + logger.warn("general parameter must be defined"); + general = []; + } + var result = []; + for ( var overlayName in this.overlayCollections) { + if (this.overlayCollections.hasOwnProperty(overlayName)) { + var overlay = this.overlayCollections[overlayName]; + if (overlay.allowGeneralSearch() || overlay.allowSearchById()) { + var generalFlag = general[overlay.getName()]; + if (generalFlag === undefined) { + logger.warn("General flag for overlay: " + overlay.getName() + + " is not defined, assuming false"); + generalFlag = false; + } + result.push({ + overlay : overlay, + data : overlay.getDetailDataByIdentifiedElement(identifiedElement, + !overlay.allowSearchById() || generalFlag) + }); + } + } + } + return result; +}; + +/** + * Returns {@link AbstractInfoWindow} for element identified by the parameter. + * + * @param identifiedElement + * {@link IdentifiedElement} that determines for which element we + * want {@link AbstractInfoWindow} + * @returns {@link AbstractInfoWindow} for element identified by the parameter + */ +CustomMap.prototype.getInfoWindowForIdentifiedElement = function( + identifiedElement) { + var model = this.getSubmodelById(identifiedElement.modelId); + var infoWindow = null; + if (identifiedElement.type == "ALIAS") { + infoWindow = model.getAliasInfoWindowById(identifiedElement.getId()); + } else if (identifiedElement.type == "POINT") { + infoWindow = model.getPointInfoWindowById(identifiedElement.getId()); + } else if (identifiedElement.type == "REACTION") { + infoWindow = model.getReactionInfoWindowById(identifiedElement.getId()); + } else { + logger.error("Unknown type of IdentifiedElement: ", identifiedElement); + } + return infoWindow; +}; + +CustomMap.prototype.getActiveSubmapId = function() { + return this._activeSubmapId; +}; + +CustomMap.prototype.setActiveSubmapId = function(submapId) { + this._activeSubmapId = submapId; +}; + +CustomMap.prototype.updateAliasesForLayout = function(layoutId, jsonAliases) { + logger.debug("Updating aliases for layout: " + layoutId); + + // init layout data + if (this.mapModel.getLayoutDataById(layoutId) == null) { + this.mapModel.initLayoutData(layoutId); + for (var i = 0; i < this.submaps.length; i++) { + this.submaps[i].mapModel.initLayoutData(layoutId); + } + } + + var aliases = JSON.parse(jsonAliases); + for (var i = 0; i < aliases.length; i++) { + var alias = aliases[i]; + var model = this.getSubmodelById(alias.modelId); + if (model != 'undefined' && model != null) { + model.mapModel.updateAliasForLayout(layoutId, alias); + model.getAliasInfoWindowById(alias.idObject).update(); + } else { + logger.warn("Unknown model: " + alias.modelId); + } + } + + this.retrieveMissingAliases(); +}; + +CustomMap.prototype.getReferenceGenome = function(type, version) { + var result = null; + if (this._referenceGenome[type] == null) { + this._referenceGenome[type] = []; + } + if (this._referenceGenome[type][version] == null) { + ServerConnector.sendReferenceGenomeDetailRequest(type, version); + this._referenceGenome[type][version] = new ReferenceGenome(null); + return null; + } else { + return this._referenceGenome[type][version]; + } +}; + +CustomMap.prototype.updateReferenceGenome = function(type, version, jsonObj) { + if (this._referenceGenome[type] == null) { + this._referenceGenome[type] = []; + } + this._referenceGenome[type][version] = new ReferenceGenome(jsonObj); + this.refreshInfoWindows(); +} diff --git a/web/src/main/webapp/resources/js/GuiConnector.js b/web/src/main/webapp/resources/js/GuiConnector.js index e5bb74b28a..85503c34d5 100644 --- a/web/src/main/webapp/resources/js/GuiConnector.js +++ b/web/src/main/webapp/resources/js/GuiConnector.js @@ -1,302 +1,302 @@ -/** - * This static global object contains set of functions that returns/set data in - * the Gui (html). - */ -GuiConnector = new Object(); - -/** - * Flag informing if the context menu is visible or not. - */ -GuiConnector.contextMenuVisible = false; - -/** - * Flag informing if selection menu is visible or not. Selection menu is - * available when selcting polygon on the map and right clicking on it. - */ -GuiConnector.selectionMenuVisible = false; - -/** - * X coordinate of the mouse in a browser. - */ -GuiConnector.xPos = 0; - -/** - * Y coordinate of the mouse in a browser. - */ -GuiConnector.yPos = 0; - -/** - * List of GET params passed via url. - */ -GuiConnector.getParams = []; - -// find GuiConnector.getParams -document.location.search.replace(/\??(?:([^=]+)=([^&]*)&?)/g, function() { - function decode(s) { - return decodeURIComponent(s.split("+").join(" ")); - } - GuiConnector.getParams[decode(arguments[1])] = decode(arguments[2]); -}); - -/** - * Initialize navigation for left panel tab. - */ -$(document) - .ready( - function() { - GuiConnector.leftPanelTabNavi = new TabNavi("tabView", { - top : "17px" - }); - GuiConnector.searchTabNavi = new TabNavi("tabView:mainForm:dTable", { - hideRemaining : false, - tabSize : 1, - top : "5px" - }); - GuiConnector.drugTabNavi = new TabNavi( - "tabView:drugForm:drugResults", { - hideRemaining : false, - tabSize : 1, - top : "5px" - }); - if (document.getElementById("tabView:chemicalForm:chemicalResults") != null) { - GuiConnector.chemicalTabNavi = new TabNavi( - "tabView:chemicalForm:chemicalResults", { - hideRemaining : false, - tabSize : 1, - top : "5px" - }); - } - GuiConnector.miRnaTabNavi = new TabNavi( - "tabView:miRNAForm:miRNAResults", { - hideRemaining : false, - tabSize : 1, - top : "5px" - }); - }); - -/** - * Returns name of the file with LCSB logo. - * - * @param bigLogo - * {@link Boolean} value determining if we want to have big logo or - * small one - */ -GuiConnector.getLcsbLogoImg = function(bigLogo) { - if (bigLogo) { - return 'lcsb_logo_mid.png'; - } else { - return 'lcsb_logo.png'; - } -}; - -/** - * Returns name of the file with image that should be presented when we are - * wainting for data to be loaded. - */ -GuiConnector.getLoadingImg = function() { - return "icons/ajax-loader.gif"; -}; - -/** - * Returns home directory for images in the application. - */ -GuiConnector.getImgPrefix = function() { - return "resources/images/"; -}; - -/** - * Returns main google maps div tag placed on the webpage. - */ -GuiConnector.getGoogleMapElement = function() { - return document.getElementById(ServerConnector.formIdentifier - + ":gmapElement"); -}; - -/** - * Shows main google map (by default map is hidden, because it doesn't point to - * our data from the beginning). - */ -GuiConnector.showGoogleMap = function() { - GuiConnector.getGoogleMapElement().style.visibility = "visible"; -}; - -/** - * Shows legend. - */ -GuiConnector.showLegend = function() { - document.getElementById(ServerConnector.formIdentifier + ':legend').style.display = "block"; -}; - -/** - * Hides legend. - */ -GuiConnector.hideLegend = function() { - document.getElementById(ServerConnector.formIdentifier + ':legend').style.display = "none"; -}; - -/** - * Hides right click menu. - */ -GuiConnector.hideRightClickMenu = function() { - $(PrimeFaces.escapeClientId(ServerConnector.formIdentifier + ':contextMenu')) - .hide(); - this.contextMenuVisible = false; -}; - -/** - * Returns <code>true</code> if right click menu is visible, - * <code>false</code> otherwise. - */ -GuiConnector.isRightMenuVisible = function() { - return this.contextMenuVisible; -}; - -/** - * Shows right click menu. - */ -GuiConnector.showRightClickMenu = function(x, y) { - $(PrimeFaces.escapeClientId(ServerConnector.formIdentifier + ':contextMenu')) - .css({ - top : y + 'px', - left : x + 'px' - }).show(); - this.contextMenuVisible = true; - - if (this.isSelectionMenuVisible) { - this.hideSelectionMenu(); - } -}; - -/** - * Hides selection menu. - * - * @see selectionMenuVisible - */ -GuiConnector.hideSelectionMenu = function() { - $( - PrimeFaces.escapeClientId(ServerConnector.formIdentifier - + ':selectionContextMenu')).hide(); - this.selectionMenuVisible = false; -}; - -/** - * Returns <code>true</code> when selection menu is visible, - * <code>false</code> otherwise. - * - * @see selectionMenuVisible - */ -GuiConnector.isSelectionMenuVisible = function() { - return this.selectionMenuVisible; -}; - -/** - * Shows selection menu. - * - * @see selectionMenuVisible - */ -GuiConnector.showSelectionMenu = function(x, y) { - $( - PrimeFaces.escapeClientId(ServerConnector.formIdentifier - + ':selectionContextMenu')).css({ - top : y + 'px', - left : x + 'px' - }).show(); - this.selectionMenuVisible = true; - - if (this.isRightMenuVisible()) { - this.hideRightClickMenu(); - } -}; - -/** - * Gets html div where overview images should be visualized. - * - */ -GuiConnector.getOverviewHtmlTag = function() { - return document.getElementById(ServerConnector.formIdentifier - + ':overviewDialog'); -}; - -/** - * Updates coordinates of the mouse in the browser. - */ -GuiConnector.updateMouseCoordinates = function(x, y) { - this.xPos = x; - this.yPos = y; -}; - -// forser browser to update mouse coordinates whenever mouse move -jQuery(document).ready(function() { - $(document).mousemove(function(e) { - GuiConnector.updateMouseCoordinates(e.pageX, e.pageY); - }); -}); - -/** - * Return html tag for submap visualization. - * - * @param id - * identifier of the submodel - */ -GuiConnector.getHtmlTagForSubmodelId = function(id) { - return document.getElementById('_gmapForm:submodelDialog' + id); -}; - -/** - * Returns js Primefaces object for submap visualization. - * - * @param id - * identifier of the submodel - */ -GuiConnector.getJsPopupForSubmodelId = function(id) { - return window['submodelDialog' + id]; -}; - -/** - * Opens popup for submap visualization. - * - * @param id - * identifier of the submodel - */ -GuiConnector.openDialog = function(id) { - var jsVar = GuiConnector.getJsPopupForSubmodelId(id); - if (jsVar != null) { - var htmlTag = GuiConnector.getHtmlTagForSubmodelId(id); - customMap.openSubmodel(id, htmlTag, jsVar); - } - return false; -}; - -GuiConnector.referenceToHtml = function(reference) { - if (reference.summary != null && reference.summary != "") { - var result = '<div title="' + reference.summary + '">'; - result += '<a href="' + reference.link + '" target="_blank">' - + reference.name + "</a>"; - // + reference.name + "(" + reference.type + ")</a>"; - result += "</div>"; - return result; - } else { - var result = '<div><a href="' + reference.link + '" target="_blank">' - + reference.name + "</a></div>"; - // + reference.name + "(" + reference.type + ")</a></div>"; - return result; - } -}; - -GuiConnector.openSearchPanel = function() { - $('a[href$="#tabView:searchTab"]').click(); -}; - -/** - * Opens window that informs user data data is being loaded from server. - */ -GuiConnector.openLoadingDialog = function() { - PF('loadingDlg').show(); -}; - -/** - * Closes window that informs user data data is being loaded from server. - */ -GuiConnector.closeLoadingDialog = function() { - PF('loadingDlg').hide(); -}; +/** + * This static global object contains set of functions that returns/set data in + * the Gui (html). + */ +GuiConnector = new Object(); + +/** + * Flag informing if the context menu is visible or not. + */ +GuiConnector.contextMenuVisible = false; + +/** + * Flag informing if selection menu is visible or not. Selection menu is + * available when selcting polygon on the map and right clicking on it. + */ +GuiConnector.selectionMenuVisible = false; + +/** + * X coordinate of the mouse in a browser. + */ +GuiConnector.xPos = 0; + +/** + * Y coordinate of the mouse in a browser. + */ +GuiConnector.yPos = 0; + +/** + * List of GET params passed via url. + */ +GuiConnector.getParams = []; + +// find GuiConnector.getParams +document.location.search.replace(/\??(?:([^=]+)=([^&]*)&?)/g, function() { + function decode(s) { + return decodeURIComponent(s.split("+").join(" ")); + } + GuiConnector.getParams[decode(arguments[1])] = decode(arguments[2]); +}); + +/** + * Initialize navigation for left panel tab. + */ +$(document) + .ready( + function() { + GuiConnector.leftPanelTabNavi = new TabNavi("tabView", { + top : "17px" + }); + GuiConnector.searchTabNavi = new TabNavi("tabView:mainForm:dTable", { + hideRemaining : false, + tabSize : 1, + top : "5px" + }); + GuiConnector.drugTabNavi = new TabNavi( + "tabView:drugForm:drugResults", { + hideRemaining : false, + tabSize : 1, + top : "5px" + }); + if (document.getElementById("tabView:chemicalForm:chemicalResults") != null) { + GuiConnector.chemicalTabNavi = new TabNavi( + "tabView:chemicalForm:chemicalResults", { + hideRemaining : false, + tabSize : 1, + top : "5px" + }); + } + GuiConnector.miRnaTabNavi = new TabNavi( + "tabView:miRNAForm:miRNAResults", { + hideRemaining : false, + tabSize : 1, + top : "5px" + }); + }); + +/** + * Returns name of the file with LCSB logo. + * + * @param bigLogo + * {@link Boolean} value determining if we want to have big logo or + * small one + */ +GuiConnector.getLcsbLogoImg = function(bigLogo) { + if (bigLogo) { + return 'lcsb_logo_mid.png'; + } else { + return 'lcsb_logo.png'; + } +}; + +/** + * Returns name of the file with image that should be presented when we are + * wainting for data to be loaded. + */ +GuiConnector.getLoadingImg = function() { + return "icons/ajax-loader.gif"; +}; + +/** + * Returns home directory for images in the application. + */ +GuiConnector.getImgPrefix = function() { + return "resources/images/"; +}; + +/** + * Returns main google maps div tag placed on the webpage. + */ +GuiConnector.getGoogleMapElement = function() { + return document.getElementById(ServerConnector.formIdentifier + + ":gmapElement"); +}; + +/** + * Shows main google map (by default map is hidden, because it doesn't point to + * our data from the beginning). + */ +GuiConnector.showGoogleMap = function() { + GuiConnector.getGoogleMapElement().style.visibility = "visible"; +}; + +/** + * Shows legend. + */ +GuiConnector.showLegend = function() { + document.getElementById(ServerConnector.formIdentifier + ':legend').style.display = "block"; +}; + +/** + * Hides legend. + */ +GuiConnector.hideLegend = function() { + document.getElementById(ServerConnector.formIdentifier + ':legend').style.display = "none"; +}; + +/** + * Hides right click menu. + */ +GuiConnector.hideRightClickMenu = function() { + $(PrimeFaces.escapeClientId(ServerConnector.formIdentifier + ':contextMenu')) + .hide(); + this.contextMenuVisible = false; +}; + +/** + * Returns <code>true</code> if right click menu is visible, + * <code>false</code> otherwise. + */ +GuiConnector.isRightMenuVisible = function() { + return this.contextMenuVisible; +}; + +/** + * Shows right click menu. + */ +GuiConnector.showRightClickMenu = function(x, y) { + $(PrimeFaces.escapeClientId(ServerConnector.formIdentifier + ':contextMenu')) + .css({ + top : y + 'px', + left : x + 'px' + }).show(); + this.contextMenuVisible = true; + + if (this.isSelectionMenuVisible) { + this.hideSelectionMenu(); + } +}; + +/** + * Hides selection menu. + * + * @see selectionMenuVisible + */ +GuiConnector.hideSelectionMenu = function() { + $( + PrimeFaces.escapeClientId(ServerConnector.formIdentifier + + ':selectionContextMenu')).hide(); + this.selectionMenuVisible = false; +}; + +/** + * Returns <code>true</code> when selection menu is visible, + * <code>false</code> otherwise. + * + * @see selectionMenuVisible + */ +GuiConnector.isSelectionMenuVisible = function() { + return this.selectionMenuVisible; +}; + +/** + * Shows selection menu. + * + * @see selectionMenuVisible + */ +GuiConnector.showSelectionMenu = function(x, y) { + $( + PrimeFaces.escapeClientId(ServerConnector.formIdentifier + + ':selectionContextMenu')).css({ + top : y + 'px', + left : x + 'px' + }).show(); + this.selectionMenuVisible = true; + + if (this.isRightMenuVisible()) { + this.hideRightClickMenu(); + } +}; + +/** + * Gets html div where overview images should be visualized. + * + */ +GuiConnector.getOverviewHtmlTag = function() { + return document.getElementById(ServerConnector.formIdentifier + + ':overviewDialog'); +}; + +/** + * Updates coordinates of the mouse in the browser. + */ +GuiConnector.updateMouseCoordinates = function(x, y) { + this.xPos = x; + this.yPos = y; +}; + +// forser browser to update mouse coordinates whenever mouse move +jQuery(document).ready(function() { + $(document).mousemove(function(e) { + GuiConnector.updateMouseCoordinates(e.pageX, e.pageY); + }); +}); + +/** + * Return html tag for submap visualization. + * + * @param id + * identifier of the submodel + */ +GuiConnector.getHtmlTagForSubmodelId = function(id) { + return document.getElementById('_gmapForm:submodelDialog' + id); +}; + +/** + * Returns js Primefaces object for submap visualization. + * + * @param id + * identifier of the submodel + */ +GuiConnector.getJsPopupForSubmodelId = function(id) { + return window['submodelDialog' + id]; +}; + +/** + * Opens popup for submap visualization. + * + * @param id + * identifier of the submodel + */ +GuiConnector.openDialog = function(id) { + var jsVar = GuiConnector.getJsPopupForSubmodelId(id); + if (jsVar != null) { + var htmlTag = GuiConnector.getHtmlTagForSubmodelId(id); + customMap.openSubmodel(id, htmlTag, jsVar); + } + return false; +}; + +GuiConnector.referenceToHtml = function(reference) { + if (reference.summary != null && reference.summary != "") { + var result = '<div title="' + reference.summary + '">'; + result += '<a href="' + reference.link + '" target="_blank">' + + reference.name + "</a>"; + // + reference.name + "(" + reference.type + ")</a>"; + result += "</div>"; + return result; + } else { + var result = '<div><a href="' + reference.link + '" target="_blank">' + + reference.name + "</a></div>"; + // + reference.name + "(" + reference.type + ")</a></div>"; + return result; + } +}; + +GuiConnector.openSearchPanel = function() { + $('a[href$="#tabView:searchTab"]').click(); +}; + +/** + * Opens window that informs user data data is being loaded from server. + */ +GuiConnector.openLoadingDialog = function() { + PF('loadingDlg').show(); +}; + +/** + * Closes window that informs user data data is being loaded from server. + */ +GuiConnector.closeLoadingDialog = function() { + PF('loadingDlg').hide(); +}; -- GitLab