Commit 60c4ae61 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

frontend starts to connect to server side via api

parent 9abf1284
......@@ -26,6 +26,11 @@
"globals" : {
"alert" : false,
/*
* custom test params
*/
"testDiv" : false,
/* MOCHA */
"describe" : false,
......
......@@ -14,6 +14,7 @@
"browserify": "^13.1.1",
"chai": "^3.5.0",
"exorcist": "^0.4.0",
"file-url": "^2.0.0",
"jquery": "3.1.1",
"jsdom": "^9.8.3",
"jshint": "^2.9.4",
......@@ -24,6 +25,8 @@
"dependencies": {
"log4js": "0.6.38",
"pileup": "^0.6.8",
"promise": "^7.1.1"
"promise": "^7.1.1",
"request": "^2.79.0",
"xmlhttprequest": "^1.8.0"
}
}
"use strict";
var ObjectWithListeners = require('./ObjectWithListeners');
/**
* Class Configuration is responsible for load a configuration from a text file
* conected to current project (in one project it is possible to show many
* maps).
*/
function Configuration(data) {
// call super constructor
ObjectWithListeners.call(this);
// set default values
this.TILE_SIZE = 256;
this.PICTURE_SIZE = 256;
this.MAX_ZOOM = 4;
this.MIN_ZOOM = 2;
this.IMG_DIR = "images/";
this.MAP_NAME = "unknown map";
this.MAPS = [];
this.SUBMODELS = [];
this.speciesAddr = "species";
this.miriamAddr = "miriam";
this.feedbackAddr = "feedback";
this.registerListenerType("onreload");
if (data !== undefined) {
this.loadFromModelView(data);
}
}
// this class inherits from ObjectWithListeners class where generic methods for
// listeners are set
Configuration.prototype = Object.create(ObjectWithListeners.prototype);
Configuration.prototype.constructor = Configuration;
/**
* Updates configuration data from object passed from server side.
*
* @param modelView
* object retrieved from server side
*/
Configuration.prototype.loadFromModelView = function(modelView) {
if (typeof modelView === "string") {
// replace is due to some strange problem with serialization
modelView = JSON.parse(modelView.replace(/\n/g, " "));
}
this.setId(parseInt(modelView.idObject));
this.TILE_SIZE = modelView.tileSize;
this.PICTURE_SIZE = modelView.pictureSize;
this.MAX_ZOOM = modelView.maxZoom;
this.MIN_ZOOM = modelView.minZoom;
this.MAP_NAME = modelView.version;
this.setCenter(modelView.centerLatLng);
this.addLayouts(modelView.layouts);
this.addLayouts(modelView.customLayouts);
this.SUBMODELS = [];
if (modelView.submodels !== undefined) {
for (var i = 0; i < modelView.submodels.length; i++) {
var conf = new Configuration();
conf.loadFromModelView(modelView.submodels[i]);
this.SUBMODELS.push(conf);
}
}
this.TOP_OVERVIEW_IMAGE = modelView.topOverviewImage;
this.OVERVIEW_IMAGES = modelView.overviewImageViews;
this.topLeftLatLng = modelView.topLeftLatLng;
this.bottomRightLatLng = modelView.bottomRightLatLng;
this.fitMapBounds = modelView.fitMapBounds;
this.callListeners("onreload");
};
Configuration.prototype.getId = function() {
return this.ID_MODEL;
};
Configuration.prototype.setId = function(id) {
this.ID_MODEL = id;
};
Configuration.prototype.setCenter = function(center) {
if (center !== undefined) {
this.CENTER_LAT = center.lat;
this.CENTER_LNG = center.lng;
}
};
Configuration.prototype.addLayout = function(layout) {
this.MAPS.push(layout);
};
Configuration.prototype.addLayouts = function(layouts) {
if (layouts !== undefined) {
this.MAPS = this.MAPS.concat(layouts);
}
};
module.exports = Configuration;
"use strict";
var ConfigurationType = {
DEFAULT_MAP : "DEFAULT_MAP",
};
module.exports = ConfigurationType;
......@@ -333,4 +333,9 @@ GuiConnector.getOverviewDialog = function() {
return _overviewDialog;
};
GuiConnector.alert = function(message) {
logger.error(message);
alert(message);
};
module.exports = GuiConnector;
......@@ -3,13 +3,18 @@
var functions = require('./Functions');
var logger = require('./logger');
var fs = require('fs');
var request = require('request');
var ConfigurationType = require('./ConfigurationType');
var Project = require('./map/data/Project');
/**
* This object contains methods that will communicate with server.
*/
var ServerConnector = {};
ServerConnector._configurationParam = [];
/**
* List of {@link OverlayCollection} that was added to the server connector. It
* describes list of all overlays that communicate with server.
......@@ -1020,19 +1025,97 @@ ServerConnector.setModelZoomLevel = function(id, zoom) {
} ]);
};
ServerConnector.readFile = function(filename, enc) {
if (enc === undefined) {
enc = 'utf8';
}
return new Promise(function(fulfill, reject) {
fs.readFile(filename, enc, function(err, res) {
if (err) {
reject(err);
ServerConnector.readFile = function(url) {
return new Promise(function(resolve, reject) {
request.get(url, function(error, response, body) {
if (error) {
reject(error);
} else if (response.statusCode !== 200) {
reject(response);
} else {
fulfill(res);
resolve(body);
}
});
});
};
ServerConnector.getToken = function() {
var self = this;
return new Promise(function(resolve) {
if (self._token === undefined) {
self.setToken(document.getElementById("authenticationForm:authenticationToken").value);
}
resolve(self._token);
});
};
ServerConnector.setToken = function(token) {
this._token = token;
};
ServerConnector.getServerBaseUrl = function() {
if (this._serverBaseUrl === undefined) {
var location = window.location;
this._serverBaseUrl = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '')
+ document.getElementById("authenticationForm:baseUrl").value;
}
return this._serverBaseUrl;
};
ServerConnector.getProjectUrl = function(projectId, token) {
return this.getServerBaseUrl() + "/api/project/getMetaData?projectId=" + projectId + "&token=" + token;
};
ServerConnector.getConfigurationUrl = function(token) {
return this.getServerBaseUrl() + "/api/configuration/getAllValues?token=" + token;
};
ServerConnector.getConfigurationParam = function(paramId) {
var self = this;
return new Promise(function(resolve, reject) {
if (paramId === undefined) {
reject("Invalid param identifier");
}
if (self._configurationParam[paramId] !== undefined) {
resolve(self._configurationParam[paramId]);
}
self.getToken().then(function(token) {
self.readFile(self.getConfigurationUrl(token)).then(function(content) {
var configs = JSON.parse(content);
for (var i = 0; i < configs.length; i++) {
var conf = configs[i];
var type = conf.type;
var value = conf.value;
self._configurationParam[type] = value;
}
resolve(self._configurationParam[paramId]);
}, reject);
}, reject);
});
};
ServerConnector.getProject = function(projectId) {
var self = this;
if (projectId === undefined || projectId === null || projectId === "") {
return new Promise(function(resolve, reject) {
self.getConfigurationParam(ConfigurationType.DEFAULT_MAP).then(function(defaultMap) {
if (defaultMap === undefined) {
reject("Cannot find default map");
}
self.getProject(defaultMap).then(function(result) {
resolve(result);
}, reject);
}, reject);
});
}
return new Promise(function(resolve, reject) {
self.getToken().then(function(token) {
self.readFile(self.getProjectUrl(projectId, token)).then(function(content) {
resolve(new Project(content));
}, reject);
}, reject);
});
};
module.exports = ServerConnector;
......@@ -6,9 +6,6 @@ var functions = require('../Functions');
var AliasInfoWindow = require('./window/AliasInfoWindow');
var AliasMarker = require('./marker/AliasMarker');
var AliasOverlay = require('./overlay/AliasOverlay');
var Configuration = require('../Configuration');
var CustomMapOptions = require('./CustomMapOptions');
var MapModel = require('./data/MapModel');
var ObjectWithListeners = require('../ObjectWithListeners');
var PointInfoWindow = require('./window/PointInfoWindow');
var PointMarker = require('./marker/PointMarker');
......@@ -18,32 +15,17 @@ var ReactionOverlay = require('./overlay/ReactionOverlay');
/**
* Default constructor.
*
* @param configuration
* {@link Configuration} used to initialize this map
*/
function AbstractCustomMap(options) {
function AbstractCustomMap(model, options) {
// call super constructor
ObjectWithListeners.call(this);
var configuration = null;
if (options instanceof Configuration) {
configuration = options;
options = new CustomMapOptions({
configuration : configuration,
map : null
});
} else if (options instanceof CustomMapOptions) {
configuration = options.getConfiguration();
this.setGoogleMap(options.getMap());
} else {
logger.error("Unknown class type of the options: ", typeof options);
if (model === undefined) {
throw Error("Model must be defined");
}
this.configuration = configuration;
// identifier of the map
this.setId(configuration.getId());
this.setGoogleMap(options.getMap());
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
......@@ -52,16 +34,12 @@ function AbstractCustomMap(options) {
// following fields are used in conversion between x,y coordinates and latlng
// coordinates
this.pixelOrigin_ = new google.maps.Point(configuration.TILE_SIZE / 2, configuration.TILE_SIZE / 2);
this.pixelsPerLonDegree_ = configuration.TILE_SIZE / 360;
this.pixelsPerLonRadian_ = configuration.TILE_SIZE / (2 * Math.PI);
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 = configuration.PICTURE_SIZE / (configuration.TILE_SIZE / (1 << configuration.MIN_ZOOM));
// map model contains information about elements on this map (data that was
// downloaded at some point)
this.mapModel = new MapModel(configuration);
this.zoomFactor = this.getPictureSize() / (this.getTileSize() / (1 << this.getMinZoom()));
// array with info windows for Marker pointing to aliases
this._aliasInfoWindow = [];
......@@ -108,17 +86,13 @@ AbstractCustomMap.prototype.constructor = AbstractCustomMap;
*
*/
AbstractCustomMap.prototype.setupLayouts = function() {
var self = this;
var onConfigurationReload = function() {
for (var i = 0; i < self.getConfiguration().MAPS.length; i++) {
var cvTypeOptions = self.createTypeOptions(self.getConfiguration().MAPS[i]);
var cvMapType = new google.maps.ImageMapType(cvTypeOptions);
self.getGoogleMap().mapTypes.set('cv' + self.getConfiguration().MAPS[i].idObject, cvMapType);
}
};
onConfigurationReload();
this.getConfiguration().addListener("onreload", onConfigurationReload);
this.getGoogleMap().setMapTypeId('cv' + self.getConfiguration().MAPS[0].idObject);
for (var i = 0; i < this.getLayouts().length; i++) {
var layout = this.getLayouts()[i];
var cvTypeOptions = this.createTypeOptions(layout);
var cvMapType = new google.maps.ImageMapType(cvTypeOptions);
this.getGoogleMap().mapTypes.set('cv' + layout.getId(), cvMapType);
}
this.getGoogleMap().setMapTypeId('cv' + this.getLayouts()[0].getId());
};
/**
......@@ -126,14 +100,14 @@ AbstractCustomMap.prototype.setupLayouts = function() {
*
*/
AbstractCustomMap.prototype.creatMapOptions = function() {
var centerPoint = new google.maps.LatLng(this.getConfiguration().CENTER_LAT, this.getConfiguration().CENTER_LNG);
var centerPoint = this.getModel().getCenterLatLng();
var result = {
center : centerPoint,
rotateControl : true,
panControl : true,
mapTypeControl : false,
zoom : this.getConfiguration().MIN_ZOOM,
zoom : this.getMinZoom(),
streetViewControl : false,
panControlOptions : {
......@@ -163,16 +137,16 @@ AbstractCustomMap.prototype.createTypeOptions = function(param) {
// 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.getConfiguration().MIN_ZOOM);
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.directory + "/" + zoom + "/" + coord.x + "/" + coord.y + ".PNG";
var addr = "../map_images/" + param.getDirectory() + "/" + zoom + "/" + coord.x + "/" + coord.y + ".PNG";
return addr;
},
tileSize : new google.maps.Size(this.getConfiguration().TILE_SIZE, this.getConfiguration().TILE_SIZE),
maxZoom : this.getConfiguration().MAX_ZOOM,
minZoom : this.getConfiguration().MIN_ZOOM,
tileSize : new google.maps.Size(this.getTileSize(), this.getTileSize()),
maxZoom : this.getMaxZoom(),
minZoom : this.getMinZoom(),
radius : 360,
name : param.name
};
......@@ -184,7 +158,7 @@ AbstractCustomMap.prototype.createTypeOptions = function(param) {
*
*/
AbstractCustomMap.prototype.setMaxZoomLevel = function() {
this.getGoogleMap().setZoom(this.getConfiguration().MAX_ZOOM);
this.getGoogleMap().setZoom(this.getMaxZoom());
};
/**
......@@ -250,8 +224,7 @@ AbstractCustomMap.prototype.getMouseLatLng = function() {
*
*/
AbstractCustomMap.prototype.fromPixelsToPoint = function(pixels, zoomLevel) {
var zoomScale = this.getConfiguration().PICTURE_SIZE
/ (Math.pow(2, zoomLevel - this.getConfiguration().MIN_ZOOM) * this.getConfiguration().TILE_SIZE);
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);
......@@ -320,8 +293,8 @@ AbstractCustomMap.prototype.fromPointToLatLng = function(point) {
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.getConfiguration().TILE_SIZE), Math
.floor(pixelCoordinate.y / this.getConfiguration().TILE_SIZE));
var tileCoordinate = new google.maps.Point(Math.floor(pixelCoordinate.x / this.getTileSize()), Math
.floor(pixelCoordinate.y / this.getTileSize()));
return tileCoordinate;
};
......@@ -584,8 +557,8 @@ AbstractCustomMap.prototype._showSelectedLayout = function(layoutId, index, leng
if (!this.initialized) {
logger.debug("Model " + this.getId() + " not initialized");
return;
} else if (this.getMapModel().getLayoutDataById(layoutId) === null
|| this.getMapModel().getLayoutDataById(layoutId) === undefined) {
} else if (this.getModel().getLayoutDataById(layoutId) === null
|| this.getModel().getLayoutDataById(layoutId) === undefined) {
logger.warn("No layout data for model " + this.getId() + ", layout: " + layoutId);
return;
} else {
......@@ -599,11 +572,11 @@ AbstractCustomMap.prototype._showSelectedLayout = function(layoutId, index, leng
// end ratio
var endX = (index + 1) * (1.0 / length);
var layoutAliases = this.getMapModel().getLayoutDataById(layoutId).aliases;
var layoutAliases = this.getModel().getLayoutDataById(layoutId).aliases;
for (var i = 0; i < layoutAliases.length; i++) {
var layoutAlias = layoutAliases[i];
var aliasData = this.getMapModel().getAliasById(layoutAlias.getId());
var aliasData = this.getModel().getAliasById(layoutAlias.getId());
if (aliasData === null || aliasData === undefined) {
logger.error("Cannot find data for alias: " + layoutAlias.getId());
} else {
......@@ -612,12 +585,12 @@ AbstractCustomMap.prototype._showSelectedLayout = function(layoutId, index, leng
}
}
var layoutReactions = this.getMapModel().getLayoutDataById(layoutId).reactions;
var layoutReactions = this.getModel().getLayoutDataById(layoutId).reactions;
for (var j = 0; j < layoutReactions.length; j++) {
var layoutReaction = layoutReactions[j];
var reactionData = this.getMapModel().getReactionById(layoutReaction.getId());
var reactionData = this.getModel().getReactionById(layoutReaction.getId());
if (reactionData === null || reactionData === undefined) {
logger.error("Cannot find data for reaction: " + layoutReaction.getId());
} else {
......@@ -661,7 +634,7 @@ AbstractCustomMap.prototype._openInfoWindowForAlias = function(aliasId) {
}
return;
} else {
this._aliasInfoWindow[aliasId] = new AliasInfoWindow(this.mapModel.getAliasById(aliasId), this);
this._aliasInfoWindow[aliasId] = new AliasInfoWindow(this.getModel().getAliasById(aliasId), this);
}
};
......@@ -678,7 +651,7 @@ AbstractCustomMap.prototype.getAliasVisibleLayoutsData = function(aliasId) {
var layouts = this.getTopMap().getSelectedLayouts();
var result = [];
for (var i = 0; i < layouts.length; i++) {
var layout = this.mapModel.getLayoutDataById(layouts[i]);
var layout = this.getModel().getLayoutDataById(layouts[i]);
if (layout !== null && layout !== undefined) {
result.push(layout.aliasById[aliasId]);
} else {
......@@ -697,10 +670,10 @@ AbstractCustomMap.prototype.getAliasVisibleLayoutsData = function(aliasId) {
* object passed from server that describes {@link Alias}
*/
AbstractCustomMap.prototype.addAlias = function(jsonObj) {
this.mapModel.addAlias(jsonObj);
this.getModel().addAlias(jsonObj);
// check if we opened window for this alias, if so then update info in it
var alias = this.mapModel.getAliasById(jsonObj.idObject);
var alias = this.getModel().getAliasById(jsonObj.idObject);
var infoWindow = this.getAliasInfoWindowById(alias.getId());
if (infoWindow !== null && infoWindow !== undefined) {
infoWindow.update(alias);
......@@ -717,7 +690,7 @@ AbstractCustomMap.prototype.getVisibleLayoutNames = function() {
var layouts = this.getTopMap().getSelectedLayouts();
var result = [];
for (var i = 0; i < layouts.length; i++) {
var layout = this.mapModel.getLayoutDataById(layouts[i]);
var layout = this.getModel().getLayoutDataById(layouts[i]);
if (layout !== null && layout !== undefined) {
result.push(layout.name);
} else {
......@@ -822,10 +795,7 @@ AbstractCustomMap.prototype.returnInfoWindowForMarker = function(marker) {
* @returns identifier
*/
AbstractCustomMap.prototype.getId = function() {
return this.id;
};
AbstractCustomMap.prototype.setId = function(id) {
this.id = id;
return this.getModel().getId();
};
/**
......@@ -843,7 +813,7 @@ AbstractCustomMap.prototype._openInfoWindowForReaction = function(reactionId) {
logger.warn("Info window for reaction: " + reactionId + " is already opened");
}
} else {
this._reactionInfoWindow[reactionId] = new ReactionInfoWindow(this.mapModel.getReactionById(reactionId), this);
this._reactionInfoWindow[reactionId] = new ReactionInfoWindow(this.getModel().getReactionById(reactionId), this);
}
};
......@@ -887,31 +857,41 @@ AbstractCustomMap.prototype.getPointInfoWindowById = function(pointId) {
* object obtained from java server side
*/
AbstractCustomMap.prototype.addReaction = function(jsonObj) {
this.getMapModel().addReaction(jsonObj);
this.getModel().addReaction(jsonObj);
// check if we opened window for this reaction, if so then update info in it
var infoWindow = this.getReactionInfoWindowById(jsonObj.idObject);
if (infoWindow !== null && infoWindow !== undefined) {
infoWindow.update(this.getMapModel().getReactionById(jsonObj.idObject));
infoWindow.update(this.getModel().getReactionById(jsonObj.idObject));
}
};
/**
* Returns {@link MapModel} connected to this {@link AbstractCustomMap}.
*
* @returns {@link MapModel} connected to this {@link AbstractCustomMap}.
*/
AbstractCustomMap.prototype.getMapModel = function() {
return this.mapModel;
AbstractCustomMap.prototype.getModel = function() {
return this._model;
};
/**
* Returns {@link Configuration} used to create this map.
*
* @returns {@link Configuration} used to create this map
*/
AbstractCustomMap.prototype.getConfiguration = function() {
return this.configuration;
AbstractCustomMap.prototype.setModel = function(model) {
this._model = model;
};
AbstractCustomMap.prototype.getTileSize = function() {
return this.getModel().getTileSize();