-
Piotr Gawron authoredPiotr Gawron authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
AbstractCustomMap.js 32.44 KiB
"use strict";
var Promise = require("bluebird");
var logger = require('../logger');
var functions = require('../Functions');
var AliasInfoWindow = require('./window/AliasInfoWindow');
var AliasMarker = require('./marker/AliasMarker');
var AliasSurface = require('./surface/AliasSurface');
var ObjectWithListeners = require('../ObjectWithListeners');
var PointData = require('./data/PointData');
var PointInfoWindow = require('./window/PointInfoWindow');
var PointMarker = require('./marker/PointMarker');
var ReactionInfoWindow = require('./window/ReactionInfoWindow');
var ReactionMarker = require('./marker/ReactionMarker');
var ReactionSurface = require('./surface/ReactionSurface');
/**
* Default constructor.
*/
function AbstractCustomMap(model, options) {
// call super constructor
ObjectWithListeners.call(this);
if (model === undefined) {
throw Error("Model must be defined");
}
this.setElement(options.getElement());
this.setModel(model);
// this array contains elements that are presented on a specific layout (set
// of google map object representing lines/areas that are associated with
// layout)
this.selectedLayoutOverlays = [];
// following fields are used in conversion between x,y coordinates and latlng
// coordinates
this.pixelOrigin_ = new google.maps.Point(this.getTileSize() / 2, this.getTileSize() / 2);
this.pixelsPerLonDegree_ = this.getTileSize() / 360;
this.pixelsPerLonRadian_ = this.getTileSize() / (2 * Math.PI);
/* jshint bitwise: false */
this.zoomFactor = this.getPictureSize() / (this.getTileSize() / (1 << this.getMinZoom()));
// array with info windows for Marker pointing to aliases
this._aliasInfoWindow = [];
// array with info windows for Marker pointing to points
this._pointInfoWindow = [];
// array with info windows for reactions
this._reactionInfoWindow = [];
// this is google.maps.drawing.DrawingManager that will allow user to draw
// elements in the client
this._drawingManager = null;
// this is the polgyon that was selected (clicked) last time on the map
this._selectedArea = null;
// markers should be optimized by default,
// however, for testing purpose this function could be turned of by javascript
// the other possibility is that it should be off in the touch mode
// (bigButtons=true)
this._markerOptimization = options.isMarkerOptimization();
this._bigLogo = options.isBigLogo();
this._customTouchInterface = options.isCustomTouchInterface();
this.setDebug(options.isDebug());
}
// define super constructor
AbstractCustomMap.prototype = Object.create(ObjectWithListeners.prototype);
AbstractCustomMap.prototype.constructor = AbstractCustomMap;
/**
* Assigns layouts with images to the google map (which set of images should be
* used by google maps api for which layout).
*
*/
AbstractCustomMap.prototype.setupLayouts = function() {
for (var i = 0; i < this.getLayouts().length; i++) {
var layout = this.getLayouts()[i];
var typeOptions = this.createTypeOptions(layout);
var mapType = new google.maps.ImageMapType(typeOptions);
this.getGoogleMap().mapTypes.set(layout.getId().toString(), mapType);
}
this.getGoogleMap().setMapTypeId(this.getLayouts()[0].getId().toString());
};
/**
* Creates general google maps options used in this map.
*
*/
AbstractCustomMap.prototype.creatMapOptions = function() {
var self = this;
var centerPoint = this.getModel().getCenterLatLng();
// if we have coordinate data stored in session then restore it
var point = ServerConnector.getSessionData(self.getProject()).getCenter(self.getModel());
if (point !== undefined) {
centerPoint = self.fromPointToLatLng(point);
}
var result = {
center : centerPoint,
rotateControl : true,
panControl : true,
mapTypeControl : false,
zoom : this.getMinZoom(),
streetViewControl : false,
panControlOptions : {
position : google.maps.ControlPosition.LEFT_TOP
},
zoomControlOptions : {
style : google.maps.ZoomControlStyle.LARGE,
position : google.maps.ControlPosition.LEFT_TOP
}
};
return result;
};
/**
* Create google maps configuration options object for a specific layout.
*
* @param param
* object with information about layout
*/
AbstractCustomMap.prototype.createTypeOptions = function(param) {
var self = this;
var result = {
// this is a function that will retrieve valid url to png images for
// tiles on different zoom levels
getTileUrl : function(coord, zoom) {
// we have 1 tile on self.getConfiguration().MIN_ZOOM and
// therefore must limit tails according to this
/* jshint bitwise: false */
var tileRange = 1 << (zoom - self.getMinZoom());
if (coord.y < 0 || coord.y >= tileRange || coord.x < 0 || coord.x >= tileRange) {
return null;
}
var addr = "../map_images/" + param.getDirectory() + "/" + zoom + "/" + coord.x + "/" + coord.y + ".PNG";
return addr;
},
tileSize : new google.maps.Size(this.getTileSize(), this.getTileSize()),
maxZoom : this.getMaxZoom(),
minZoom : this.getMinZoom(),
radius : 360,
name : param.name
};
return result;
};
/**
* Sets maximum zoom level on google map.
*
*/
AbstractCustomMap.prototype.setMaxZoomLevel = function() {
this.getGoogleMap().setZoom(this.getMaxZoom());
};
/**
* Returns mouse coordinate on the map in lat,lng system.
*
*/
AbstractCustomMap.prototype.getMouseLatLng = function() {
// this method is tricky, the main problem is how to map mouse coordinate to
// google map
// to do that we need a point of reference in both systems (x,y and lat,lng)
// this will be center of the map that is currently visible
// next, we will have to find distance from this point in x,y coordinates and
// transform it to lat,lng
var self = this;
// center point visible on the map
var coord = self.getGoogleMap().getCenter();
var point = self.fromLatLngToPoint(coord);
// this is magic :)
// find offset of the div where google map is located related to top left
// corner of the browser
var el = self.getGoogleMap().getDiv();
for (var lx = 0, ly = 0; el !== null && el !== undefined; lx += el.offsetLeft, ly += el.offsetTop, el = el.offsetParent) {
}
var offset = {
x : lx,
y : ly
};
var center = {
x : self.getGoogleMap().getDiv().offsetWidth / 2,
y : self.getGoogleMap().getDiv().offsetHeight / 2
};
// and now find how far from center point we are (in pixels)
var relativeDist = {
x : (GuiConnector.xPos - offset.x - center.x),
y : (GuiConnector.yPos - offset.y - center.y)
};
// transform pixels into x,y distance
var pointDist = self.fromPixelsToPoint(relativeDist, self.getGoogleMap().getZoom());
// now we have offset in x,y and center point on the map in x,y, so we have
// final position in x,y
var newCoord = new google.maps.Point(point.x + pointDist.x, point.y + pointDist.y);
// change it to lat,lng
var latLngResult = self.fromPointToLatLng(newCoord);
return latLngResult;
};
/**
* Transform distance (coordinates) in pixels into x,y distance on the map.
*
* @param pixels
* x,y distance in pixels
* @param zoomLevel
* at which zoom level this pixels where mesaured
*
*/
AbstractCustomMap.prototype.fromPixelsToPoint = function(pixels, zoomLevel) {
var zoomScale = this.getPictureSize() / (Math.pow(2, zoomLevel - this.getMinZoom()) * this.getTileSize());
var pointx = pixels.x * zoomScale;
var pointy = pixels.y * zoomScale;
return new google.maps.Point(pointx, pointy);
};
/**
* Transforms coordinates on the map from google.maps.LatLng to
* google.maps.Point
*
* @param latlng
* cooordinates in x,y format
* @param coordinates
* in lat,lng format
*/
AbstractCustomMap.prototype.fromLatLngToPoint = function(latLng) {
var me = this;
var point = new google.maps.Point(0, 0);
var origin = me.pixelOrigin_;
point.x = origin.x + latLng.lng() * me.pixelsPerLonDegree_;
// Truncating to 0.9999 effectively limits latitude to 89.189. This is
// about a third of a tile past the edge of the world tile.
var siny = functions.bound(Math.sin(functions.degreesToRadians(latLng.lat())), -0.9999, 0.9999);
point.y = origin.y + 0.5 * Math.log((1 + siny) / (1 - siny)) * -me.pixelsPerLonRadian_;
// rescale the point (all computations are done assuming that we work on
// TILE_SIZE square)
point.x *= me.zoomFactor;
point.y *= me.zoomFactor;
return point;
};
/**
* Transforms coordinates on the map from google.maps.Point to
* google.maps.LatLng
*
* @param point
* coordinates in standard x,y format
* @return cooordinates in lat,lng format
*/
AbstractCustomMap.prototype.fromPointToLatLng = function(point) {
var me = this;
// rescale the point (all computations are done assuming that we work on
// TILE_SIZE square)
var p = new google.maps.Point(point.x / me.zoomFactor, point.y / me.zoomFactor);
var origin = me.pixelOrigin_;
var lng = (p.x - origin.x) / me.pixelsPerLonDegree_;
var latRadians = (p.y - origin.y) / -me.pixelsPerLonRadian_;
var lat = functions.radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2);
return new google.maps.LatLng(lat, lng);
};
/**
* Transforms google.maps.LatLng to tile coordinate (for instance on which tile
* mouse clicked).
*
*
* @param latlng
* coordinates in latlng format
* @param z
* zoom level at which we want to find coordinates of tile
* @return cooordinates of a tile
*/
AbstractCustomMap.prototype.latLngToTile = function(latLng, z) {
var worldCoordinate = this.fromLatLngToPoint(latLng);
var pixelCoordinate = new google.maps.Point(worldCoordinate.x * Math.pow(2, z), worldCoordinate.y * Math.pow(2, z));
var tileCoordinate = new google.maps.Point(Math.floor(pixelCoordinate.x / this.getTileSize()), Math
.floor(pixelCoordinate.y / this.getTileSize()));
return tileCoordinate;
};
/**
* Register events responsible for click events
*/
AbstractCustomMap.prototype.registerMapClickEvents = function() {
// find top map (CustomMap)
//
var customMap = this.getTopMap();
var self = this;
// search event
google.maps.event.addListener(this.getGoogleMap(), 'click', function(mouseEvent) {
var point = self.fromLatLngToPoint(mouseEvent.latLng);
var searchDb = customMap.getOverlayByName('search');
return searchDb.searchByCoordinates({
modelId : self.getModel().getId(),
coordinates : point,
zoom : self.getGoogleMap().getZoom()
}).then(null, GuiConnector.alert);
});
// select last clicked map
google.maps.event.addListener(this.getGoogleMap(), 'click', function(mouseEvent) {
customMap.setActiveSubmapId(self.getId());
customMap.setActiveSubmapClickCoordinates(self.fromLatLngToPoint(mouseEvent.latLng));
});
// select last clicked map
google.maps.event.addListener(this.getGoogleMap(), 'rightclick', function(mouseEvent) {
customMap.setActiveSubmapId(self.getId());
customMap.setActiveSubmapClickCoordinates(self.fromLatLngToPoint(mouseEvent.latLng));
});
// prepare for image export
google.maps.event.addListener(this.getGoogleMap(), 'rightclick', function() {
var bounds = self.getGoogleMap().getBounds();
var polygon = "";
var ne = bounds.getNorthEast();
var sw = bounds.getSouthWest();
var westLng = sw.lng();
var eastLng = ne.lng();
if (westLng > 0) {
westLng = -180;
}
if (eastLng - westLng > 90) {
eastLng = -90;
} else if (eastLng > -90) {
eastLng = -90;
}
polygon += ne.lat() + "," + westLng + ";";
polygon += ne.lat() + "," + eastLng + ";";
polygon += sw.lat() + "," + eastLng + ";";
polygon += sw.lat() + "," + westLng + ";";
self.getTopMap().setSelectedPolygon(polygon);
});
// context menu event
google.maps.event.addListener(this.getGoogleMap(), 'rightclick', function() {
self.getTopMap().getContextMenu().open(GuiConnector.xPos, GuiConnector.yPos);
});
};
/**
* It toggle drawing manager used on the map: if it's on then it will turn it
* off, if it's off it will turn it on
*
*/
AbstractCustomMap.prototype._turnOnOffDrawing = function() {
if (this.isDrawingOn()) {
this.turnOffDrawing();
} else {
this.turnOnDrawing();
}
};
/**
* Checks if the drawing manager for the map is on.
*
*/
AbstractCustomMap.prototype.isDrawingOn = function() {
return this._drawingManager !== null;
};
/**
* Turns on drawing manager on the map.
*/
AbstractCustomMap.prototype.turnOnDrawing = function() {
if (this.isDrawingOn()) {
logger.warn("Trying to turn on drawing manager, but it is already available.");
return;
}
var customMap = this.getTopMap();
var self = this;
this._drawingManager = new google.maps.drawing.DrawingManager({
drawingMode : google.maps.drawing.OverlayType.MARKER,
drawingControl : true,
drawingControlOptions : {
position : google.maps.ControlPosition.TOP_CENTER,
drawingModes : [ google.maps.drawing.OverlayType.POLYGON, ]
},
markerOptions : {
icon : 'images/beachflag.png'
},
circleOptions : {
fillColor : '#ffff00',
fillOpacity : 1,
strokeWeight : 5,
clickable : false,
editable : true,
zIndex : 1
}
});
this._drawingManager.setMap(this.getGoogleMap());
this._drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON);
google.maps.event.addListener(this._drawingManager, 'overlaycomplete', function(e) {
if (e.type !== google.maps.drawing.OverlayType.MARKER) {
// Switch back to non-drawing mode after drawing a shape.
self._drawingManager.setDrawingMode(null);
// Add an event listener that selects the newly-drawn shape when the
// user mouses down on it.
var newShape = e.overlay;
newShape.type = e.type;
google.maps.event.addListener(newShape, 'rightclick', function(e) {
// select map that was clicked
customMap.setActiveSubmapId(self.getId());
self.setSelectedArea(newShape);
newShape.position = e.latLng;
self.getTopMap().setSelectedPolygon(self.areaToString(newShape));
self.getTopMap().getSelectionContextMenu().open(GuiConnector.xPos, GuiConnector.yPos);
});
}
});
};
/**
* Sets selectedArea on this map.
*
*/
AbstractCustomMap.prototype.setSelectedArea = function(area) {
this._selectedArea = area;
};
/**
* Returns selectedArea on this map.
*
*/
AbstractCustomMap.prototype.getSelectedArea = function() {
return this._selectedArea;
};
/**
* Transforms google.maps.Polygon into string with coordinates.
*
*/
AbstractCustomMap.prototype.areaToString = function(area) {
var len = area.getPath().length;
var path = area.getPath();
var res = "";
for (var i = 0; i < len; i++) {
var latLng = path.getAt(i);
res += latLng.lat() + "," + latLng.lng() + ";";
}
return res;
};
/**
* Removes selected area (polygon) from the map.
*/
AbstractCustomMap.prototype._removeSelection = function() {
if (this._selectedArea) {
this._selectedArea.setMap(null);
this._selectedArea = null;
} else {
logger.warn("Cannot remove selected area. No area was selected");
}
};
/**
* Turns off drawing manager on the map.
*/
AbstractCustomMap.prototype.turnOffDrawing = function() {
if (this.isDrawingOn()) {
this._drawingManager.setMap(null);
this._drawingManager = null;
} else {
logger.warn("Trying to turn off drawing manager, but it is not available.");
}
};
/**
* Returns top map. TODO implementation of this function should be probably
* moved to Submap and CustomMap classes and here only abstract function
* definition
*
* @returns {CustomMap}
*/
AbstractCustomMap.prototype.getTopMap = function() {
logger.fatal("Not implemented");
};
/**
* Method that should be called when number of layouts to visualize changed to
* modify boundaries of the elements to visualize. When few layouts are
* visualized at the same time then index contains information where this new
* layout is placed in the list (starting from 0) and length contains
* information how many layouts we visualize in total.
*
* @param layoutId
* identifier of a layout
* @param index
* when visualizing more than one layout at the same time index
* contains information at which position in the list this layout is
* placed
* @param length
* number of layouts that are currently visualized
*/
AbstractCustomMap.prototype._resizeSelectedLayout = function(layoutId, index, length) {
var self = this;
return new Promise(function(resolve) {
// if map is not initialized then don't perform this operation
if (!self.initialized) {
logger.debug("Model " + self.getId() + " not initialized");
resolve();
}
logger.debug("Resize layout: " + layoutId);
// start ratio
var startX = index * (1.0 / length);
// end ratio
var endX = (index + 1) * (1.0 / length);
for (var i = 0; i < self.selectedLayoutOverlays[layoutId].length; i++) {
self.selectedLayoutOverlays[layoutId][i].setBoundsForAlias(startX, endX);
}
resolve();
});
};
/**
* Shows all elements from a given layout. When few layouts are visualized at
* the same time then index contains information where this new layout is placed
* in the list (starting from 0) and length contains information how many
* layouts we visualize in total.
*
* @param layoutId
* identifier of a layout
* @param index
* when visualizing more than one layout at the same time index
* contains information at which position in the list this layout is
* placed
* @param length
* number of layouts that are currently visualized
*/
AbstractCustomMap.prototype._showSelectedLayout = function(layoutId, index, length) {
var self = this;
// if map is not initialized then don't perform this operation
return new Promise(function(resolve, reject) {
if (!self.initialized) {
logger.debug("Model " + self.getId() + " not initialized");
resolve();
return;
} else {
logger.debug("Showing model " + self.getId());
}
self.selectedLayoutOverlays[layoutId] = [];
// start ratio
var startX = index * (1.0 / length);
// end ratio
var endX = (index + 1) * (1.0 / length);
var layoutAliases;
var layoutReactions;
return self.getTopMap().getModel().getLayoutDataById(layoutId).then(function(layout) {
layoutAliases = layout.getAliases();
layoutReactions = layout.getReactions();
return Promise.each(layoutAliases, function(layoutAlias) {
if (layoutAlias.getModelId() === self.getId()) {
return self.getModel().getAliasById(layoutAlias.getId()).then(function(aliasData) {
return AliasSurface.create(layoutAlias, aliasData, self, startX, endX);
}).then(function(overlay) {
self.selectedLayoutOverlays[layoutId].push(overlay);
});
}
});
}).then(function() {
return Promise.each(layoutReactions, function(layoutReaction) {
if (layoutReaction.getModelId() === self.getId()) {
return self.getModel().getReactionById(layoutReaction.getId()).then(function(reactionData) {
var reactionOverlay = new ReactionSurface({
layoutReaction : layoutReaction,
reaction : reactionData,
map : self,
customized : (length === 1)
});
self.selectedLayoutOverlays[layoutId].push(reactionOverlay);
reactionOverlay.show();
});
}
});
}).then(function() {
resolve();
}).then(null, reject);
});
};
/**
* Hides all elements from layout.
*
* @param layoutId
* identifier of a layout
*/
AbstractCustomMap.prototype._hideSelectedLayout = function(layoutId) {
// if map is not initialized then don't perform this operation
if (!this.initialized) {
logger.debug("Model " + this.getId() + " not initialized");
return;
}
for (var i = 0; i < this.selectedLayoutOverlays[layoutId].length; i++) {
this.selectedLayoutOverlays[layoutId][i].setMap(null);
}
this.selectedLayoutOverlays[layoutId] = [];
};
/**
* Opens {@link AliasInfoWindow} for given alias.
*
* @param aliasId
* identifier of the alias
*/
AbstractCustomMap.prototype._openInfoWindowForAlias = function(alias, googleMarker) {
var self = this;
var infoWindow = this.getAliasInfoWindowById(alias.getId());
if (infoWindow !== null && infoWindow !== undefined) {
if (!infoWindow.isOpened()) {
infoWindow.open();
} else {
logger.warn("Info window for alias: " + alias.getId() + " is already opened");
}
return Promise.resolve(infoWindow);
} else {
self._aliasInfoWindow[alias.getId()] = new AliasInfoWindow({
alias : alias,
map : self,
marker : googleMarker,
});
return self._aliasInfoWindow[alias.getId()].init();
}
};
/**
* Returns promise of a list of {@link LayoutAlias} information for a given
* {@link Alias} in all currently visualized layouts.
*
* @param aliasId
* identifier of the {@link Alias}
* @returns promise of an {Array} with list of {@link LayoutAlias} information
* for a given {@link Alias} in all currently visualized layouts
*/
AbstractCustomMap.prototype.getAliasVisibleLayoutsData = function(aliasId) {
var self = this;
return self.getTopMap().getVisibleDataOverlays().then(function(visibleDataOverlays) {
var result = [];
for (var i = 0; i < visibleDataOverlays.length; i++) {
var layout = visibleDataOverlays[i];
result.push(layout.getFullAliasById(aliasId));
}
return Promise.all(result);
});
};
/**
* Refresh content of all {@link AliasInfoWindow} in this map.
*/
AbstractCustomMap.prototype._refreshInfoWindows = function() {
var promises = [];
for ( var key in this._pointInfoWindow) {
if (this._pointInfoWindow.hasOwnProperty(key)) {
if (this._pointInfoWindow[key].isOpened()) {
promises.push(this._pointInfoWindow[key].update());
}
}
}
for ( var aliasKey in this._aliasInfoWindow) {
if (this._aliasInfoWindow.hasOwnProperty(aliasKey)) {
if (this._aliasInfoWindow[aliasKey].isOpened()) {
promises.push(this._aliasInfoWindow[aliasKey].update());
}
}
}
return Promise.all(promises);
};
/**
* Opens {@link AbstractInfoWindow} for a marker.
*
* @param marker
* marker for which we are opening window
*/
AbstractCustomMap.prototype._openInfoWindowForIdentifiedElement = function(element, googleMarker) {
var self = this;
if (element.getType() === "ALIAS") {
return self.getModel().getByIdentifiedElement(element).then(function(alias) {
return self._openInfoWindowForAlias(alias, googleMarker);
});
} else if (element.getType() === "POINT") {
return self._openInfoWindowForPoint(new PointData(element), googleMarker);
} else if (element.getType() === "REACTION") {
return self.getModel().getByIdentifiedElement(element).then(function(reaction) {
return self._openInfoWindowForReaction(reaction, googleMarker);
});
} else {
throw new Error("Unknown element type: " + element.getType());
}
};
AbstractCustomMap.prototype._openInfoWindowForReaction = function(reaction, googleMarker) {
var self = this;
var reactionInfoWindow = this.getReactionInfoWindowById(reaction.getId());
if (reactionInfoWindow !== null && reactionInfoWindow !== undefined) {
if (!reactionInfoWindow.isOpened()) {
reactionInfoWindow.open();
} else {
logger.warn("Info window for reaction: " + reaction.getId() + " is already opened");
}
return Promise.resolve();
} else {
this._reactionInfoWindow[reaction.getId()] = new ReactionInfoWindow({
reaction : reaction,
map : self,
marker : googleMarker,
});
return this._reactionInfoWindow[reaction.getId()].init();
}
};
AbstractCustomMap.prototype._openInfoWindowForPoint = function(pointData, googleMarker) {
var self = this;
var infoWindow = this.getPointInfoWindowById(pointData.getId());
if (infoWindow !== null && infoWindow !== undefined) {
if (!infoWindow.isOpened()) {
infoWindow.open();
} else {
logger.warn("Info window for point: " + element.getId() + " is already opened");
}
} else {
infoWindow = new PointInfoWindow({
point : pointData,
map : self,
marker : googleMarker,
});
this._pointInfoWindow[pointData.getId()] = infoWindow;
}
return Promise.resolve(infoWindow);
};
/**
* Opens {@link AbstractInfoWindow} for a marker.
*
* @param marker
* marker for which we are opening window
*/
AbstractCustomMap.prototype.returnInfoWindowForIdentifiedElement = function(element) {
var markerId = element.getId();
if (element.getType() === "ALIAS") {
return this.getAliasInfoWindowById(markerId);
} else if (element.getType() === "POINT") {
return this.getPointInfoWindowById(markerId);
} else if (element.getType() === "REACTION") {
return this.getReactionInfoWindowById(markerId);
} else {
throw new Error("Unknown marker type: ", marker);
}
};
/**
* Returns identifier.
*
* @returns identifier
*/
AbstractCustomMap.prototype.getId = function() {
return this.getModel().getId();
};
/**
* Opens {@link ReactionInfoWindow} for given reaction identifier.
*
* @param reactionId
* reaction identifier
*/
AbstractCustomMap.prototype._openInfoWindowForReaction = function(reaction, googleMarker) {
var infoWindow = this.getReactionInfoWindowById(reaction.getId());
var self = this;
if (infoWindow !== null && infoWindow !== undefined) {
if (!infoWindow.isOpened()) {
infoWindow.open();
} else {
logger.warn("Info window for reaction: " + reactionId + " is already opened");
}
return Promise.resolve(infoWindow);
} else {
return self.getModel().getReactionById(reaction.getId()).then(function(reaction) {
infoWindow = new ReactionInfoWindow({
reaction : reaction,
map : self,
marker : googleMarker,
});
self._reactionInfoWindow[reaction.getId()] = infoWindow;
return infoWindow.init();
}).then(function() {
return infoWindow;
});
}
};
AbstractCustomMap.prototype._createMapChangedCallbacks = function() {
var self = this;
var sessionData = ServerConnector.getSessionData(self.getTopMap().getProject());
// listener for changing zoom level
google.maps.event.addListener(this.getGoogleMap(), 'zoom_changed', function() {
sessionData.setZoomLevel(self.getModel(), self.getGoogleMap().getZoom());
});
// listener for changing location of the map (moving left/reght/top/bottom
google.maps.event.addListener(this.getGoogleMap(), 'center_changed', function() {
var coord = self.getGoogleMap().getCenter();
var point = self.fromLatLngToPoint(coord);
sessionData.setCenter(self.getModel(), point);
});
};
/**
* Returns {@link ReactionInfoWindow} for given reaction identifier
*
* @param reactionId
* reaction identifier
* @returns {@link ReactionInfoWindow} for given reaction identifier
*/
AbstractCustomMap.prototype.getReactionInfoWindowById = function(reactionId) {
return this._reactionInfoWindow[reactionId];
};
/**
* Returns {@link AliasInfoWindow} for given alias identifier
*
* @param aliasId
* alias identifier
* @returns {@link AliasInfoWindow} for given alias identifier
*/
AbstractCustomMap.prototype.getAliasInfoWindowById = function(aliasId) {
return this._aliasInfoWindow[aliasId];
};
/**
* Returns {@link PointInfoWindow} for given point identifier
*
* @param pointId
* point identifier
* @returns {@link PointInfoWindow} for given point identifier
*/
AbstractCustomMap.prototype.getPointInfoWindowById = function(pointId) {
return this._pointInfoWindow[pointId];
};
AbstractCustomMap.prototype.getModel = function() {
return this._model;
};
AbstractCustomMap.prototype.setModel = function(model) {
this._model = model;
};
AbstractCustomMap.prototype.getTileSize = function() {
return this.getModel().getTileSize();
};
AbstractCustomMap.prototype.getMinZoom = function() {
return this.getModel().getMinZoom();
};
AbstractCustomMap.prototype.getMaxZoom = function() {
return this.getModel().getMaxZoom();
};
AbstractCustomMap.prototype.getLayouts = function() {
return this.getModel().getLayouts();
};
AbstractCustomMap.prototype.getPictureSize = function() {
return this.getModel().getPictureSize();
};
/**
* Returns array containining elements that are presented on a specific layout
* (set of google map objects representing lines/areas that are associated with
* layout).
*
* @returns {Array} containining elements that are presented on a specific
* layout (set of google map objects representing lines/areas that are
* associated with layout).
*/
AbstractCustomMap.prototype.getSelectedLayoutOverlays = function() {
return this.selectedLayoutOverlays;
};
/**
* Returns google.maps.map object used to representing data.
*
* @returns google.maps.map object used to representing data
*/
AbstractCustomMap.prototype.getGoogleMap = function() {
return this._map;
};
/**
* Sets google.maps.map object used to representing data.
*
*/
AbstractCustomMap.prototype.setGoogleMap = function(gmap) {
this._map = gmap;
};
AbstractCustomMap.prototype.isMarkerOptimization = function() {
return this._markerOptimization;
};
AbstractCustomMap.prototype.isBigLogo = function() {
return this._bigLogo;
};
AbstractCustomMap.prototype.isCustomTouchInterface = function() {
return this._customTouchInterface;
};
AbstractCustomMap.prototype.setDebug = function(debug) {
if (debug !== undefined) {
if (typeof debug !== "boolean") {
logger.warn("param must be boolean");
}
this._debug = debug;
}
};
AbstractCustomMap.prototype.isDebug = function() {
return this._debug === true;
};
AbstractCustomMap.prototype.getTopLeftLatLng = function() {
return this.getModel().getTopLeftLatLng();
};
AbstractCustomMap.prototype.getBottomRightLatLng = function() {
return this.getModel().getBottomRightLatLng();
};
AbstractCustomMap.prototype.getElement = function() {
return this._element;
};
AbstractCustomMap.prototype.setElement = function(element) {
this._element = element;
};
/**
* Sets center point for google maps.
*
* @param coordinates
* new center point on map
*/
AbstractCustomMap.prototype.setCenter = function(coordinates) {
if (coordinates instanceof google.maps.Point) {
coordinates = this.fromPointToLatLng(coordinates);
}
if (this.initialized) {
return Promise.resolve(this.getGoogleMap().setCenter(coordinates));
} else {
logger.warn("cannot center map that is not opened yet");
return Promise.resolve();
}
};
/**
* Sets zoom level for google maps.
*
* @param mapIdentifier
* id of the model for which we change zoom level
* @param zoom
* new zoom level on map
*/
AbstractCustomMap.prototype.setZoom = function(zoom) {
if (this.initialized) {
return Promise.resolve(this.getGoogleMap().setZoom(zoom));
} else {
logger.warn("cannot center map that is not opened yet");
return Promise.resolve();
}
};
AbstractCustomMap.prototype.fitBounds = function(markers) {
var self = this;
var map = self.getGoogleMap();
if (map !== undefined) {
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < markers.length; i++) {
var marker = markers[i];
if (marker.getModelId() === self.getId()) {
var markerBounds = marker.getBounds();
bounds.extend(markerBounds.getNorthEast());
bounds.extend(markerBounds.getSouthWest());
}
}
if (!bounds.isEmpty()) {
map.fitBounds(bounds);
}
}
};
module.exports = AbstractCustomMap;